This is an automated email from the ASF dual-hosted git repository.

sblackmon pushed a commit to branch feat-5-graphdb
in repository https://gitbox.apache.org/repos/asf/streams-activitypub.git

commit 1df84c3d698cd800a7606c3b40ffe626628fe465
Author: Steve Blackmon <sblack...@apache.org>
AuthorDate: Sun Feb 18 20:52:17 2024 -0600

    feat: integrate with fuseki (graph database+api) #5
    
    resolves #5 : **Add a graph module and a Webfinger implementation using 
jena graphdb binding**
    
    - adds a real implementation of webfinger protocol which responds only to 
requests for entities that exist in the configured fuseki triple-store
    - tests capabilities at the WebfingerApi Graph implementation level, and 
within the packaged webapp
    - apache/streams-activitypub docker image now runs 
streams-activitypub-webapp and jena-fuseki2-webapp
    
    Signed-off-by: Steve Blackmon <sblack...@apache.org>
---
 pom.xml                                            |  48 +++++++-
 streams-activitypub-api/pom.xml                    |   5 +-
 .../api/test/WebfingerApiTestImpl.scala            |  15 +++
 streams-activitypub-dist/Dockerfile                |   5 +-
 streams-activitypub-dist/pom.xml                   |  57 +++++++++-
 .../pom.xml                                        | 103 +++++++++++++----
 .../graph/config/WebfingerGraphImplConfig.json     |  20 ++++
 .../queries/webfingerAskByResource.sparql          |   4 +
 .../queries/webfingerGetByResource.sparql          |   9 ++
 .../src/main/resources/reference.conf              |   3 +
 .../graph/impl/WebfingerGraphImpl.scala            |  92 +++++++++++++++
 .../ActivityPubGraphTestSuiteExtensionConfig.json  |  25 ++++
 .../src/test/resources/application.conf            |   9 ++
 .../graph/test/ActivityPubGraphTestSuite.scala     |  29 +++++
 .../test/ActivityPubGraphTestSuiteExtension.scala  |  82 ++++++++++++++
 .../cases/GraphDatabaseServerAvailableTest.scala   |  40 +++++++
 .../graph/test/cases/WebfingerGraphImplTest.scala  | 126 +++++++++++++++++++++
 streams-activitypub-remote/pom.xml                 |  20 ++--
 streams-activitypub-servlets/pom.xml               |   7 +-
 .../activitypub/servlets/WebfingerServlet.scala    | 118 ++++++++-----------
 .../pom.xml                                        |  53 +++------
 .../util/AcctPrefixResourceToResourceURISwap.scala |  39 +++++++
 .../test/scala/AcctPrefixResourceURISwapTest.scala |  34 ++++++
 streams-activitypub-webapp/pom.xml                 |  60 ++++++++++
 .../src/test/resources/application.conf            |   9 ++
 .../webapp/test/ActivityPubWebappTestSuite.scala   |  11 +-
 .../test/ActivityPubWebappTestSuiteExtension.scala |  22 +---
 .../webapp/test/cases/RootServletTest.scala        |  17 ++-
 .../test/cases/ServletRegistrationTest.scala       |  27 +++--
 ...eTest.scala => WebappServerAvailableTest.scala} |  24 ++--
 .../webapp/test/cases/WebfingerServletTest.scala   |  41 +++++--
 31 files changed, 937 insertions(+), 217 deletions(-)

diff --git a/pom.xml b/pom.xml
index 5940755..6e4325c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -365,6 +365,8 @@
         <jackson.version>2.16.0</jackson.version>
         <jakarta.version>6.0.0</jakarta.version>
         <jakarta-ws.version>3.1.0</jakarta-ws.version>
+        <jena.version>5.0.0-rc1</jena.version>
+        <jetty.version>12.0.6</jetty.version>
         <joda-convert.version>1.8.1</joda-convert.version>
         <joda-time.version>2.9.9</joda-time.version>
         <json-path.version>2.8.0</json-path.version>
@@ -417,14 +419,22 @@
         <module>streams-activitypub-actors</module>
         <module>streams-activitypub-api</module>
         <module>streams-activitypub-dist</module>
+        <module>streams-activitypub-graph</module>
         <module>streams-activitypub-remote</module>
         <module>streams-activitypub-servlets</module>
+        <module>streams-activitypub-utils</module>
         <module>streams-activitypub-webapp</module>
     </modules>
 
     <packaging>pom</packaging>
 
     <build>
+        <testResources>
+            <testResource>
+                <directory>${project.basedir}</directory>
+                <filtering>true</filtering>
+            </testResource>
+        </testResources>
         <extensions>
             <extension>
                 <groupId>org.apache.maven.wagon</groupId>
@@ -553,19 +563,34 @@
                     <artifactId>jsonschema2pojo-maven-plugin</artifactId>
                     <version>${jsonschema2pojo.version}</version>
                     <configuration>
+                        <addCompileSourceRoot>true</addCompileSourceRoot>
                         <annotationStyle>none</annotationStyle>
                         
<customAnnotator>org.apache.streams.plugins.JuneauPojoAnnotator</customAnnotator>
                         <generateBuilders>true</generateBuilders>
                         
<includeGeneratedAnnotation>false</includeGeneratedAnnotation>
-                        
<sourceDirectory>${project.basedir}/src/main/jsonschema</sourceDirectory>
-                        
<outputDirectory>${project.build.directory}/generated-sources/pojo</outputDirectory>
                     </configuration>
                     <executions>
                         <execution>
-                            <phase>generate-sources</phase>
+                            <id>generate-sources</id>
+                            <phase>none</phase>
+                            <goals>
+                                <goal>generate</goal>
+                            </goals>
+                            <configuration>
+                                
<sourceDirectory>${project.basedir}/src/main/jsonschema</sourceDirectory>
+                                
<outputDirectory>${project.build.directory}/generated-sources/pojo</outputDirectory>
+                            </configuration>
+                        </execution>
+                        <execution>
+                            <id>generate-test-sources</id>
+                            <phase>none</phase>
                             <goals>
                                 <goal>generate</goal>
                             </goals>
+                            <configuration>
+                                
<sourceDirectory>${project.basedir}/src/test/jsonschema</sourceDirectory>
+                                
<outputDirectory>${project.build.directory}/generated-test-sources/pojo</outputDirectory>
+                            </configuration>
                         </execution>
                     </executions>
                     <dependencies>
@@ -628,6 +653,18 @@
                                 </sources>
                             </configuration>
                         </execution>
+                        <execution>
+                            <id>add-generated-test-sources</id>
+                            <phase>generate-test-sources</phase>
+                            <goals>
+                                <goal>add-source</goal>
+                            </goals>
+                            <configuration>
+                                <sources>
+                                    
<source>target/generated-test-sources/pojo</source>
+                                </sources>
+                            </configuration>
+                        </execution>
                     </executions>
                 </plugin>
                 <plugin>
@@ -1467,6 +1504,11 @@
                             <argLine>--add-opens=java.base/java.io=ALL-UNNAMED 
--add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED</argLine>
                             <skipTests>${skipTests}</skipTests>
                             <skipExec>${skipExec}</skipExec>
+                            <properties>
+                                <configurationParameters>
+                                    
junit.jupiter.testclass.order.default=org.junit.jupiter.api.ClassOrderer$OrderAnnotation
+                                </configurationParameters>
+                            </properties>
                         </configuration>
                     </plugin>
                 </plugins>
diff --git a/streams-activitypub-api/pom.xml b/streams-activitypub-api/pom.xml
index a759d5f..3ffca62 100755
--- a/streams-activitypub-api/pom.xml
+++ b/streams-activitypub-api/pom.xml
@@ -81,13 +81,10 @@
             <plugin>
                 <groupId>org.jsonschema2pojo</groupId>
                 <artifactId>jsonschema2pojo-maven-plugin</artifactId>
-                <version>1.2.1</version>
+                <version>${jsonschema2pojo.version}</version>
                 <executions>
                     <execution>
                         <id>generate-sources</id>
-                        <goals>
-                            <goal>generate</goal>
-                        </goals>
                         <phase>generate-sources</phase>
                     </execution>
                 </executions>
diff --git 
a/streams-activitypub-api/src/test/scala/org/apache/streams/activitypub/api/test/WebfingerApiTestImpl.scala
 
b/streams-activitypub-api/src/test/scala/org/apache/streams/activitypub/api/test/WebfingerApiTestImpl.scala
new file mode 100755
index 0000000..a01db5a
--- /dev/null
+++ 
b/streams-activitypub-api/src/test/scala/org/apache/streams/activitypub/api/test/WebfingerApiTestImpl.scala
@@ -0,0 +1,15 @@
+package org.apache.streams.activitypub.api.test
+
+import org.apache.streams.activitypub.api.WebfingerApi
+import org.apache.streams.activitypub.api.pojo.WebfingerQueryRequest
+import org.apache.streams.activitypub.api.pojo.WebfingerQueryResponse
+
+class WebfingerApiTestImpl extends WebfingerApi {
+
+  def webfingerQuery(request: WebfingerQueryRequest): WebfingerQueryResponse = 
{
+
+    new WebfingerQueryResponse().withSubject(request.getResource)
+
+  }
+
+}
diff --git a/streams-activitypub-dist/Dockerfile 
b/streams-activitypub-dist/Dockerfile
index 28f42c0..8534e27 100644
--- a/streams-activitypub-dist/Dockerfile
+++ b/streams-activitypub-dist/Dockerfile
@@ -2,4 +2,7 @@ FROM tomcat:jre17-temurin
 MAINTAINER d...@streams.apache.org
 LABEL Description="apache-streams-activitypub-dist"
 WORKDIR /
-ADD target/exploded /usr/local/tomcat/webapps/ROOT
+RUN mkdir -p /etc/fuseki
+ADD target/lib/* /usr/local/tomcat/lib/
+ADD target/webapps/streams-activitypub.war /usr/local/tomcat/webapps/ROOT.war
+ADD target/webapps/jena-fuseki.war /usr/local/tomcat/webapps/fuseki.war
diff --git a/streams-activitypub-dist/pom.xml b/streams-activitypub-dist/pom.xml
index 3616898..a2274ef 100755
--- a/streams-activitypub-dist/pom.xml
+++ b/streams-activitypub-dist/pom.xml
@@ -42,25 +42,74 @@ under the License.
     </dependencies>
 
     <build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+            </resource>
+        </resources>
+        <testResources>
+            <testResource>
+                <directory>src/test/resources</directory>
+            </testResource>
+        </testResources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
-                       <id>unpack</id>
-                       <phase>prepare-package</phase>
+                       <id>copy</id>
+                       <phase>package</phase>
                        <goals>
-                           <goal>unpack</goal>
+                           <goal>copy</goal>
                        </goals>
                        <configuration>
-                           
<outputDirectory>${project.build.directory}/exploded</outputDirectory>
                            <artifactItems>
                                <artifactItem>
                                    
<groupId>org.apache.streams.activitypub</groupId>
                                    
<artifactId>streams-activitypub-webapp</artifactId>
                                    <version>${project.version}</version>
                                    <type>war</type>
+                                   
<outputDirectory>${project.build.directory}/webapps</outputDirectory>
+                                   <overWrite>true</overWrite>
+                                   
<destFileName>streams-activitypub.war</destFileName>
+                               </artifactItem>
+                               <artifactItem>
+                                   <groupId>org.apache.jena</groupId>
+                                   <artifactId>jena-fuseki-war</artifactId>
+                                   <version>${jena.version}</version>
+                                   <type>war</type>
+                                   
<outputDirectory>${project.build.directory}/webapps</outputDirectory>
+                                   <overWrite>true</overWrite>
+                                   <destFileName>jena-fuseki.war</destFileName>
+                               </artifactItem>
+                               <!-- the fuseki war excludes some needed 
dependencies -->
+                               <artifactItem>
+                                   <groupId>org.eclipse.jetty</groupId>
+                                   <artifactId>jetty-http</artifactId>
+                                   <version>${jetty.version}</version>
+                                   <type>jar</type>
+                                   
<outputDirectory>${project.build.directory}/lib</outputDirectory>
+                                   <overWrite>true</overWrite>
+                                   <destFileName>jetty-http.jar</destFileName>
+                               </artifactItem>
+                               <artifactItem>
+                                   <groupId>org.eclipse.jetty</groupId>
+                                   <artifactId>jetty-util</artifactId>
+                                   <version>${jetty.version}</version>
+                                   <type>jar</type>
+                                   
<outputDirectory>${project.build.directory}/lib</outputDirectory>
+                                   <overWrite>true</overWrite>
+                                   <destFileName>jetty-util.jar</destFileName>
+                               </artifactItem>
+                               <artifactItem>
+                                   <groupId>org.slf4j</groupId>
+                                   <artifactId>slf4j-api</artifactId>
+                                   <version>${slf4j.version}</version>
+                                   <type>jar</type>
+                                   
<outputDirectory>${project.build.directory}/lib</outputDirectory>
+                                   <overWrite>true</overWrite>
+                                   <destFileName>slf4j-api.jar</destFileName>
                                </artifactItem>
                            </artifactItems>
                        </configuration>
diff --git a/streams-activitypub-api/pom.xml b/streams-activitypub-graph/pom.xml
old mode 100755
new mode 100644
similarity index 52%
copy from streams-activitypub-api/pom.xml
copy to streams-activitypub-graph/pom.xml
index a759d5f..f340313
--- a/streams-activitypub-api/pom.xml
+++ b/streams-activitypub-graph/pom.xml
@@ -28,26 +28,52 @@
         <relativePath>../pom.xml</relativePath>
     </parent>
 
-    <artifactId>streams-activitypub-api</artifactId>
-    <description>Apache Streams ActivityPub Server APIs</description>
+    <artifactId>streams-activitypub-graph</artifactId>
+    <description>Apache Streams Graph</description>
     <name>${project.artifactId}</name>
     <packaging>jar</packaging>
 
     <dependencies>
 
         <dependency>
-            <groupId>org.apache.streams</groupId>
-            <artifactId>streams-config</artifactId>
+            <groupId>org.apache.streams.activitypub</groupId>
+            <artifactId>streams-activitypub-api</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.streams.activitypub</groupId>
+            <artifactId>streams-activitypub-utils</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <!-- streams-graph only dependencies -->
+        <dependency>
+            <groupId>org.apache.jena</groupId>
+            <artifactId>jena-arq</artifactId>
+            <version>${jena.version}</version>
+            <type>jar</type>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.jena</groupId>
+            <artifactId>jena-rdfconnection</artifactId>
+            <version>${jena.version}</version>
+            <type>jar</type>
+        </dependency>
 
-        <!-- streams-api only dependencies -->
+        <!-- streams-graph test dependencies -->
+        <dependency>
+            <groupId>org.apache.jena</groupId>
+            <artifactId>jena-fuseki-main</artifactId>
+            <version>${jena.version}</version>
+            <type>jar</type>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>org.apache.juneau</groupId>
-            <artifactId>juneau-rest-common</artifactId>
+            <artifactId>juneau-rest-client</artifactId>
             <version>${juneau.version}</version>
+            <scope>test</scope>
         </dependency>
-
     </dependencies>
     <build>
         <sourceDirectory>src/main/scala</sourceDirectory>
@@ -64,37 +90,72 @@
         </testResources>
         <plugins>
             <plugin>
-                <groupId>net.alchim31.maven</groupId>
-                <artifactId>scala-maven-plugin</artifactId>
-                <configuration>
-                    <source>${project.basedir}/src/main/scala</source>
-                    <scalaVersion>${scala.version}</scalaVersion>
-                </configuration>
+                <groupId>org.jsonschema2pojo</groupId>
+                <artifactId>jsonschema2pojo-maven-plugin</artifactId>
+                <version>${jsonschema2pojo.version}</version>
+                <executions>
+                    <execution>
+                        <id>generate-sources</id>
+                        <phase>generate-sources</phase>
+                    </execution>
+                    <execution>
+                        <id>generate-test-sources</id>
+                        <phase>generate-test-sources</phase>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
                 <executions>
                     <execution>
                         <goals>
-                            <goal>compile</goal>
+                            <goal>jar</goal>
+                            <goal>test-jar</goal>
                         </goals>
                     </execution>
                 </executions>
             </plugin>
             <plugin>
-                <groupId>org.jsonschema2pojo</groupId>
-                <artifactId>jsonschema2pojo-maven-plugin</artifactId>
-                <version>1.2.1</version>
+                <groupId>net.alchim31.maven</groupId>
+                <artifactId>scala-maven-plugin</artifactId>
                 <executions>
                     <execution>
-                        <id>generate-sources</id>
+                        <id>scala-compile</id>
+                        <phase>compile</phase>
                         <goals>
-                            <goal>generate</goal>
+                            <goal>compile</goal>
                         </goals>
-                        <phase>generate-sources</phase>
                     </execution>
                 </executions>
+                <configuration>
+                    <addScalacArgs>--explain</addScalacArgs>
+                    <scalaVersion>${scala.version}</scalaVersion>
+                </configuration>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-jar-plugin</artifactId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-resources</id>
+                        <phase>process-test-resources</phase>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>
+                        <configuration>
+                            
<outputDirectory>${project.build.testOutputDirectory}</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>..</directory>
+                                    <includes>
+                                        <include>*.ttl</include>
+                                    </includes>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                </executions>
             </plugin>
         </plugins>
     </build>
diff --git 
a/streams-activitypub-graph/src/main/jsonschema/org/apache/streams/activitypub/graph/config/WebfingerGraphImplConfig.json
 
b/streams-activitypub-graph/src/main/jsonschema/org/apache/streams/activitypub/graph/config/WebfingerGraphImplConfig.json
new file mode 100755
index 0000000..51250f8
--- /dev/null
+++ 
b/streams-activitypub-graph/src/main/jsonschema/org/apache/streams/activitypub/graph/config/WebfingerGraphImplConfig.json
@@ -0,0 +1,20 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema";,
+  "id": "#",
+  "type": "object",
+  "javaType": 
"org.apache.streams.activitypub.graph.config.WebfingerGraphImplConfig",
+  "javaInterfaces": [
+    "java.io.Serializable"
+  ],
+  "properties": {
+    "fusekiEndpointURI": {
+      "type": "string",
+      "format": "uri",
+      "required": true
+    },
+    "defaultDatasetId": {
+      "type": "string",
+      "required": false
+    }
+  }
+}
diff --git 
a/streams-activitypub-graph/src/main/resources/queries/webfingerAskByResource.sparql
 
b/streams-activitypub-graph/src/main/resources/queries/webfingerAskByResource.sparql
new file mode 100644
index 0000000..72c64dc
--- /dev/null
+++ 
b/streams-activitypub-graph/src/main/resources/queries/webfingerAskByResource.sparql
@@ -0,0 +1,4 @@
+BASE <>
+ASK {
+    ?resourceParam ?p ?o
+}
diff --git 
a/streams-activitypub-graph/src/main/resources/queries/webfingerGetByResource.sparql
 
b/streams-activitypub-graph/src/main/resources/queries/webfingerGetByResource.sparql
new file mode 100644
index 0000000..75d98da
--- /dev/null
+++ 
b/streams-activitypub-graph/src/main/resources/queries/webfingerGetByResource.sparql
@@ -0,0 +1,9 @@
+BASE <>
+PREFIX r: <classpath://WebfingerQueryResponse.json>
+CONSTRUCT {
+    <r:response> <#subject> ?resource .
+    <r:response> <#alias> ?alias
+} WHERE {
+    BIND( ?resourceParam as ?resource )
+
+}
diff --git a/streams-activitypub-graph/src/main/resources/reference.conf 
b/streams-activitypub-graph/src/main/resources/reference.conf
new file mode 100644
index 0000000..b60d46c
--- /dev/null
+++ b/streams-activitypub-graph/src/main/resources/reference.conf
@@ -0,0 +1,3 @@
+WebfingerGraphImpl = {
+  fusekiEndpointURI = "http://localhost:8080/fuseki/";
+}
diff --git 
a/streams-activitypub-graph/src/main/scala/org/apache/streams/activitypub/graph/impl/WebfingerGraphImpl.scala
 
b/streams-activitypub-graph/src/main/scala/org/apache/streams/activitypub/graph/impl/WebfingerGraphImpl.scala
new file mode 100644
index 0000000..6237e16
--- /dev/null
+++ 
b/streams-activitypub-graph/src/main/scala/org/apache/streams/activitypub/graph/impl/WebfingerGraphImpl.scala
@@ -0,0 +1,92 @@
+package org.apache.streams.activitypub.graph.impl
+
+import org.apache.http.client.utils.URIBuilder
+import org.apache.jena.query.ParameterizedSparqlString
+import org.apache.jena.rdf.model.Model
+import org.apache.jena.riot.system.PrefixMapStd
+import org.apache.jena.sparql.exec.http.QueryExecutionHTTP
+import org.apache.jena.sparql.exec.http.QueryExecutionHTTPBuilder
+import org.apache.streams.activitypub.api.WebfingerApi
+import org.apache.streams.activitypub.api.pojo.WebfingerQueryRequest
+import org.apache.streams.activitypub.api.pojo.WebfingerQueryResponse
+import org.apache.streams.activitypub.graph.config.WebfingerGraphImplConfig
+import org.apache.streams.activitypub.util.AcctPrefixResourceToResourceURISwap
+import org.apache.streams.config.ComponentConfigurator
+
+import java.net.URI
+import scala.io.Source;
+
+object WebfingerGraphImpl {
+
+  private final val configurator: 
ComponentConfigurator[WebfingerGraphImplConfig] = new 
ComponentConfigurator(classOf[WebfingerGraphImplConfig])
+  final val config: WebfingerGraphImplConfig = 
configurator.detectConfiguration()
+  final val DEFAULT: WebfingerGraphImpl = new WebfingerGraphImpl(config)
+
+}
+
+class WebfingerGraphImpl(config: WebfingerGraphImplConfig) extends 
WebfingerApi {
+
+  private def serverUri = new URIBuilder(config.getFusekiEndpointURI).build()
+
+  private def datasetQueryUri = new 
URIBuilder(serverUri).setPath(s"${config.getDefaultDatasetId}/query").build()
+
+  final val sparqlBuilder: QueryExecutionHTTPBuilder = 
QueryExecutionHTTP.service(datasetQueryUri.toString).postQuery()
+
+  val prefixMap = new PrefixMapStd()
+
+  /**
+   * Query the dataset for the requested resource.
+   * @param request
+   * @return
+   */
+  override def webfingerQuery(request: WebfingerQueryRequest): 
WebfingerQueryResponse = {
+
+    val resourceParamURI: URI = request.getResource match {
+      case s"acct:$x" => AcctPrefixResourceToResourceURISwap.doUnswap(x)
+      case _ => new URI(request.getResource)
+    }
+
+    val askQueryBody: String = 
Source.fromResource("queries/webfingerAskByResource.sparql").getLines.mkString
+    val askQuery: ParameterizedSparqlString = new 
ParameterizedSparqlString(askQueryBody)
+    askQuery.setIri("resourceParam", resourceParamURI.toString)
+    val askExecution: QueryExecutionHTTP = 
sparqlBuilder.query(askQuery.asQuery()).build()
+    val askResult = askExecution.execAsk()
+    if( !askResult ) throw new Exception("Requested resource not found in 
dataset.")
+
+    val constructQueryBody: String = 
Source.fromResource("queries/webfingerGetByResource.sparql").getLines.mkString
+    val constructQuery: ParameterizedSparqlString = new 
ParameterizedSparqlString(constructQueryBody)
+    constructQuery.setIri("resourceParam", resourceParamURI.toString)
+    val constructExecution: QueryExecutionHTTP = 
sparqlBuilder.query(constructQuery.asQuery()).build()
+    val model: Model = constructExecution.execConstruct()
+
+    //    val result = writer.write(System.out, constructed, prefixMap, 
RDFFormat.JSONLD_FRAME_PRETTY, context);
+    if( checkModelContainsSubject( resourceParamURI, model ) ) {
+      generateResponse(request, model, resourceParamURI)
+    } else throw new Exception("Error generating response.")
+  }
+
+  /**
+   * Check if the model returned from the query contains the requested resource
+   * and necessary details to generate a valid response.
+   * @param request
+   * @param model
+   * @return
+   */
+  def checkModelContainsSubject(resourceParamURI: URI, model: Model): Boolean 
= {
+    model.containsResource(model.getResource(resourceParamURI.toString))
+  }
+
+  /**
+   * Translate the model into a webfinger response object.
+   * @param request
+   * @param model
+   * @return
+   */
+  def generateResponse(request: WebfingerQueryRequest, model: Model, 
resourceParamURI: URI): WebfingerQueryResponse = {
+    val subject = model.getResource(resourceParamURI.toString)
+    val result = new WebfingerQueryResponse()
+      .withSubject(subject.getURI)
+    result
+  }
+
+}
diff --git 
a/streams-activitypub-graph/src/test/jsonschema/ActivityPubGraphTestSuiteExtensionConfig.json
 
b/streams-activitypub-graph/src/test/jsonschema/ActivityPubGraphTestSuiteExtensionConfig.json
new file mode 100755
index 0000000..a1e2606
--- /dev/null
+++ 
b/streams-activitypub-graph/src/test/jsonschema/ActivityPubGraphTestSuiteExtensionConfig.json
@@ -0,0 +1,25 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema";,
+  "id": "#",
+  "type": "object",
+  "javaType": 
"org.apache.streams.activitypub.graph.test.config.ActivityPubGraphTestSuiteExtensionConfig",
+  "javaInterfaces": [
+    "java.io.Serializable"
+  ],
+  "properties": {
+    "fusekiEndpointURI": {
+      "type": "string",
+      "format": "uri",
+      "required": true
+    },
+    "testDatasetResource": {
+      "type": "string",
+      "format": "uri",
+      "required": true
+    },
+    "testDatasetId": {
+      "type": "string",
+      "required": true
+    }
+  }
+}
diff --git a/streams-activitypub-graph/src/test/resources/application.conf 
b/streams-activitypub-graph/src/test/resources/application.conf
new file mode 100644
index 0000000..fde8a62
--- /dev/null
+++ b/streams-activitypub-graph/src/test/resources/application.conf
@@ -0,0 +1,9 @@
+ActivityPubGraphTestSuiteExtensionConfig = {
+  fusekiEndpointURI = "http://localhost:13330/";
+  testDatasetResource = "doap.ttl"
+  testDatasetId = "doap.ttl"
+}
+WebfingerGraphImplConfig = {
+  fusekiEndpointURI = "http://localhost:13330/";
+  defaultDatasetId = "doap.ttl"
+}
diff --git 
a/streams-activitypub-graph/src/test/scala/org/apache/streams/activitypub/graph/test/ActivityPubGraphTestSuite.scala
 
b/streams-activitypub-graph/src/test/scala/org/apache/streams/activitypub/graph/test/ActivityPubGraphTestSuite.scala
new file mode 100755
index 0000000..e8b32c5
--- /dev/null
+++ 
b/streams-activitypub-graph/src/test/scala/org/apache/streams/activitypub/graph/test/ActivityPubGraphTestSuite.scala
@@ -0,0 +1,29 @@
+package org.apache.streams.activitypub.graph.test
+
+import org.junit.jupiter.api.Order
+import org.junit.jupiter.api.extension.RegisterExtension
+import org.junit.platform.suite.api.SelectClasses
+import org.junit.platform.suite.api.Suite
+import org.junit.platform.suite.api.SuiteDisplayName;
+
+/**
+ * ActivityPubServletsTestSuite
+ */
+
+object ActivityPubGraphTestSuite {
+
+  @RegisterExtension
+  given fuseki: ActivityPubGraphTestSuiteExtension = new 
ActivityPubGraphTestSuiteExtension()
+
+}
+
+@Suite
+@SuiteDisplayName("ActivityPub Graph Integration Tests")
+@Order(Order.DEFAULT)
+@SelectClasses(Array(
+  
classOf[org.apache.streams.activitypub.graph.test.cases.GraphDatabaseServerAvailableTest],
+  
classOf[org.apache.streams.activitypub.graph.test.cases.WebfingerGraphImplTest]
+))
+class ActivityPubGraphTestSuite {
+
+}
diff --git 
a/streams-activitypub-graph/src/test/scala/org/apache/streams/activitypub/graph/test/ActivityPubGraphTestSuiteExtension.scala
 
b/streams-activitypub-graph/src/test/scala/org/apache/streams/activitypub/graph/test/ActivityPubGraphTestSuiteExtension.scala
new file mode 100644
index 0000000..553c729
--- /dev/null
+++ 
b/streams-activitypub-graph/src/test/scala/org/apache/streams/activitypub/graph/test/ActivityPubGraphTestSuiteExtension.scala
@@ -0,0 +1,82 @@
+package org.apache.streams.activitypub.graph.test
+
+import org.apache.http.client.utils.URIBuilder
+import org.apache.http.impl.NoConnectionReuseStrategy
+import org.apache.jena.fuseki.main.FusekiServer
+import org.apache.jena.query.Dataset
+import org.apache.jena.query.DatasetFactory
+import org.apache.jena.riot.RDFDataMgr
+import org.apache.juneau.rest.client.RestClient
+import org.apache.streams.activitypub.graph.config.WebfingerGraphImplConfig
+import org.apache.streams.activitypub.graph.impl.WebfingerGraphImpl
+import 
org.apache.streams.activitypub.graph.test.config.ActivityPubGraphTestSuiteExtensionConfig
+import org.apache.streams.config.ComponentConfigurator
+import org.junit.jupiter.api.extension.AfterAllCallback
+import org.junit.jupiter.api.extension.BeforeAllCallback
+import org.junit.jupiter.api.extension.ExtensionContext
+import org.junit.jupiter.api.extension.ParameterContext
+import org.junit.jupiter.api.extension.ParameterResolver
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+
+import java.net.URL
+
+object ActivityPubGraphTestSuiteExtension {
+  private final val configurator: 
ComponentConfigurator[ActivityPubGraphTestSuiteExtensionConfig] = new 
ComponentConfigurator(classOf[ActivityPubGraphTestSuiteExtensionConfig])
+  final val config: ActivityPubGraphTestSuiteExtensionConfig = 
configurator.detectConfiguration()
+}
+
+class ActivityPubGraphTestSuiteExtension extends ParameterResolver with 
BeforeAllCallback with AfterAllCallback {
+
+  import ActivityPubGraphTestSuiteExtension.config
+
+  private final val LOGGER: Logger = 
LoggerFactory.getLogger(classOf[ActivityPubGraphTestSuiteExtension])
+
+  private val dataset : Dataset = DatasetFactory.create()
+  private val serverBuilder : FusekiServer.Builder = FusekiServer.create()
+
+  RDFDataMgr.read(dataset, config.getTestDatasetResource.toString)
+
+  private val server: FusekiServer = serverBuilder
+    .add(config.getTestDatasetId, dataset)
+    .enablePing(true)
+    .loopback(true)
+    .port(config.getFusekiEndpointURI.getPort)
+    .verbose(true)
+    .build();
+  server.start();
+
+  val serverUrl = new URL(server.serverURL())
+  val datasetUrl = new URL(server.datasetURL(config.getTestDatasetId))
+  val serverUrlBuilder = new URIBuilder(serverUrl.toURI)
+  val datasetUrlBuilder = new URIBuilder(datasetUrl.toURI)
+
+  def restClientBuilder: RestClient.Builder = RestClient.create()
+    .connectionReuseStrategy(new NoConnectionReuseStrategy())
+    .debug()
+    .disableAutomaticRetries()
+    .disableCookieManagement()
+    .disableRedirectHandling()
+    .maxConnTotal(10)
+    .rootUrl(serverUrl)
+
+  def restClient: RestClient = restClientBuilder
+    .pooled()
+    .build();
+
+  override def beforeAll(context : ExtensionContext) : Unit = {
+    LOGGER.info("beforeAll()");
+  }
+
+  override def afterAll(extensionContext: ExtensionContext): Unit = {
+    LOGGER.info("afterAll()")
+  }
+
+  override def supportsParameter(parameterContext: ParameterContext, 
extensionContext: ExtensionContext): Boolean = {
+    
parameterContext.getParameter.getType.equals(classOf[ActivityPubGraphTestSuiteExtension])
+  }
+
+  override def resolveParameter(parameterContext: ParameterContext, 
extensionContext: ExtensionContext): AnyRef = {
+    this
+  }
+}
diff --git 
a/streams-activitypub-graph/src/test/scala/org/apache/streams/activitypub/graph/test/cases/GraphDatabaseServerAvailableTest.scala
 
b/streams-activitypub-graph/src/test/scala/org/apache/streams/activitypub/graph/test/cases/GraphDatabaseServerAvailableTest.scala
new file mode 100755
index 0000000..3e8eb79
--- /dev/null
+++ 
b/streams-activitypub-graph/src/test/scala/org/apache/streams/activitypub/graph/test/cases/GraphDatabaseServerAvailableTest.scala
@@ -0,0 +1,40 @@
+package org.apache.streams.activitypub.graph.test.cases
+
+import org.apache.http.HttpStatus
+import 
org.apache.streams.activitypub.graph.test.ActivityPubGraphTestSuiteExtension
+import org.awaitility.Awaitility.await
+import org.junit.jupiter.api.Assertions
+import org.junit.jupiter.api.DisplayName
+import org.junit.jupiter.api.Order
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import org.slf4j.LoggerFactory
+
+import scala.concurrent.duration.MINUTES
+import scala.concurrent.duration.SECONDS
+import scala.util.Try;
+
+/**
+ * ActivityPubServletsTestSuite
+ */
+@ExtendWith(Array(classOf[ActivityPubGraphTestSuiteExtension]))
+class GraphDatabaseServerAvailableTest {
+
+  private final val LOGGER = 
LoggerFactory.getLogger(classOf[GraphDatabaseServerAvailableTest]);
+
+  @Test
+  @DisplayName("Verify Fuseki Online")
+  @Order(0)
+  def testGraphDatabaseServerOnline(using helper : 
ActivityPubGraphTestSuiteExtension): Unit = {
+    val testAttempt = Try {
+      await atMost(1, MINUTES) pollInterval(1, SECONDS) until {
+        () => Try {
+          val request = helper.restClient.get("/$/ping")
+          val response = request.run()
+          response.getStatusCode == HttpStatus.SC_OK
+        }.isSuccess
+      }
+    }
+    Assertions.assertTrue(testAttempt.isSuccess, "Graph Database Server is 
available")
+  }
+}
diff --git 
a/streams-activitypub-graph/src/test/scala/org/apache/streams/activitypub/graph/test/cases/WebfingerGraphImplTest.scala
 
b/streams-activitypub-graph/src/test/scala/org/apache/streams/activitypub/graph/test/cases/WebfingerGraphImplTest.scala
new file mode 100755
index 0000000..da05f3a
--- /dev/null
+++ 
b/streams-activitypub-graph/src/test/scala/org/apache/streams/activitypub/graph/test/cases/WebfingerGraphImplTest.scala
@@ -0,0 +1,126 @@
+package org.apache.streams.activitypub.graph.test.cases
+
+import org.apache.http.HttpStatus
+import org.apache.http.client.utils.URIBuilder
+import org.apache.http.entity.ContentType
+import org.apache.streams.activitypub.api.pojo.WebfingerQueryRequest
+import org.apache.streams.activitypub.api.pojo.WebfingerQueryResponse
+import org.apache.streams.activitypub.graph.impl.WebfingerGraphImpl
+import org.apache.streams.activitypub.graph.test.ActivityPubGraphTestSuite
+import org.junit.jupiter.api.Assertions
+import org.junit.jupiter.api.Disabled
+import org.junit.jupiter.api.DisplayName
+import org.junit.jupiter.api.Order
+import org.junit.jupiter.api.Test
+import org.slf4j.LoggerFactory
+
+import java.nio.charset.Charset
+import scala.util.Try;
+
+class WebfingerGraphImplTest {
+
+    private final val LOGGER = 
LoggerFactory.getLogger(classOf[GraphDatabaseServerAvailableTest]);
+
+    val primaryTestResourceURI = "https://mastodon.social/users/steveblackmon";
+
+    /**
+     * Test webfinger lookup of a known resource, using abbreviated 'acct:' 
prefix form
+     * @throws java.lang.Exception
+     */
+    @Test
+    @DisplayName("WebfingerQuery For Known Abbreviated Resource")
+    @Order(1)
+    def testWebfingerQueryForKnownAbbreviatedResource() : Unit = {
+        val knownAbbreviatedResource = "acct:steveblackmon@mastodon.social"
+        val testWebfingerGraphImpl = WebfingerGraphImpl.DEFAULT
+        val request = new WebfingerQueryRequest()
+        request.setResource(knownAbbreviatedResource)
+        val response: WebfingerQueryResponse = 
testWebfingerGraphImpl.webfingerQuery(request)
+        Assertions.assertNotNull(response)
+        
Assertions.assertTrue(response.getSubject.equals(primaryTestResourceURI))
+    }
+
+    /**
+     * Test webfinger lookup of a known resource, using official indexed URI 
form
+     *
+     * @throws java.lang.Exception
+     */
+    @Test
+    @DisplayName("WebfingerQuery For Known URI Resource")
+    @Order(1)
+    def testWebfingerQueryForKnownUriResource(): Unit = {
+        val knownPrimaryResourceUri = primaryTestResourceURI
+        val testWebfingerGraphImpl = WebfingerGraphImpl.DEFAULT
+        val request = new WebfingerQueryRequest()
+        request.setResource(knownPrimaryResourceUri)
+        val response: WebfingerQueryResponse = 
testWebfingerGraphImpl.webfingerQuery(request)
+        Assertions.assertNotNull(response)
+        
Assertions.assertTrue(response.getSubject.equals(primaryTestResourceURI))
+    }
+
+    /**
+     * Test webfinger lookup of a known resource, using common alternative 
non-indexed URI form
+     * This test requires the ask and construct queries to be able to match 
the alias form,
+     * without the alias URI being in the graph.
+     * @throws java.lang.Exception
+     */
+    @Disabled("alias inference not yet implemented")
+    @Test
+    @DisplayName("WebfingerQuery For Known Alias")
+    @Order(1)
+    def testWebfingerQueryForKnownAlias(): Unit = {
+        val knownAliasUri = "https://mastodon.social/@steveblackmon";
+        val testWebfingerGraphImpl = WebfingerGraphImpl.DEFAULT
+        val request = new WebfingerQueryRequest()
+        request.setResource(knownAliasUri)
+        val response: WebfingerQueryResponse = 
testWebfingerGraphImpl.webfingerQuery(request)
+        Assertions.assertNotNull(response)
+        
Assertions.assertTrue(response.getSubject.equals(primaryTestResourceURI))
+    }
+
+    /**
+     * Test that webfinger lookup of a non-present resource fails with 
exception
+     * @throws java.lang.Exception
+     */
+    @Test
+    @DisplayName("WebfingerQuery For Missing URI Resource")
+    @Order(2)
+    def testWebfingerQueryForMissingUriResource(): Unit = {
+        val testWebfingerGraphImpl = WebfingerGraphImpl.DEFAULT
+        val request = new WebfingerQueryRequest()
+        request.setResource("https://mastodon.social/users/joeschmo";)
+        val attempt = Try(testWebfingerGraphImpl.webfingerQuery(request))
+        Assertions.assertTrue(attempt.isFailure)
+    }
+
+    /**
+     * Test that webfinger lookup of a non-present abbreviated form resource 
fails with exception
+     * @throws java.lang.Exception
+     */
+    @Test
+    @DisplayName("WebfingerQuery For Missing Abbreviated Resource")
+    @Order(2)
+    def testWebfingerQueryForMissingAbbreviatedResource(): Unit = {
+        val testWebfingerGraphImpl = WebfingerGraphImpl.DEFAULT
+        val request = new WebfingerQueryRequest()
+        request.setResource("acct:joeschmo@mastodon.social")
+        val attempt = Try(testWebfingerGraphImpl.webfingerQuery(request))
+        Assertions.assertTrue(attempt.isFailure)
+    }
+
+    /**
+     * Test that webfinger lookup with a malformed abbreviated prefix resource 
fails with exception
+     *
+     * @throws java.lang.Exception
+     */
+    @Test
+    @DisplayName("WebfingerQuery For Atypical Prefixed Resource")
+    @Order(2)
+    def testWebfingerQueryForAtypicalPrefixedResource(): Unit = {
+        val testWebfingerGraphImpl = WebfingerGraphImpl.DEFAULT
+        val request = new WebfingerQueryRequest()
+        request.setResource("account:steveblackmon@mastodon.social")
+        val attempt = Try(testWebfingerGraphImpl.webfingerQuery(request))
+        Assertions.assertTrue(attempt.isFailure)
+    }
+}
diff --git a/streams-activitypub-remote/pom.xml 
b/streams-activitypub-remote/pom.xml
index 19ffa4f..0b876f7 100755
--- a/streams-activitypub-remote/pom.xml
+++ b/streams-activitypub-remote/pom.xml
@@ -58,16 +58,16 @@
     </dependencies>
     <build>
         <sourceDirectory>src/main/scala</sourceDirectory>
-<!--        <resources>-->
-<!--            <resource>-->
-<!--                <directory>src/main/resources</directory>-->
-<!--            </resource>-->
-<!--        </resources>-->
-<!--        <testResources>-->
-<!--            <testResource>-->
-<!--                <directory>src/test/resources</directory>-->
-<!--            </testResource>-->
-<!--        </testResources>-->
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+            </resource>
+        </resources>
+        <testResources>
+            <testResource>
+                <directory>src/test/resources</directory>
+            </testResource>
+        </testResources>
         <plugins>
             <plugin>
                 <groupId>net.alchim31.maven</groupId>
diff --git a/streams-activitypub-servlets/pom.xml 
b/streams-activitypub-servlets/pom.xml
index 1d67334..b64edf5 100755
--- a/streams-activitypub-servlets/pom.xml
+++ b/streams-activitypub-servlets/pom.xml
@@ -29,7 +29,7 @@
     <artifactId>streams-activitypub-servlets</artifactId>
     <name>${project.artifactId}</name>
 
-    <description>Apache Streams Resource Classes (Servlets)</description>
+    <description>Apache Streams Servlet Classes</description>
 
     <packaging>jar</packaging>
 
@@ -49,6 +49,11 @@
             <artifactId>streams-activitypub-remote</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.streams.activitypub</groupId>
+            <artifactId>streams-activitypub-graph</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.apache.juneau</groupId>
             <artifactId>juneau-rest-server</artifactId>
diff --git 
a/streams-activitypub-servlets/src/main/scala/org/apache/streams/activitypub/servlets/WebfingerServlet.scala
 
b/streams-activitypub-servlets/src/main/scala/org/apache/streams/activitypub/servlets/WebfingerServlet.scala
index cf7fb7d..a38277f 100755
--- 
a/streams-activitypub-servlets/src/main/scala/org/apache/streams/activitypub/servlets/WebfingerServlet.scala
+++ 
b/streams-activitypub-servlets/src/main/scala/org/apache/streams/activitypub/servlets/WebfingerServlet.scala
@@ -1,33 +1,21 @@
 package org.apache.streams.activitypub.servlets;
 
 import jakarta.servlet.ServletConfig
-import org.apache.commons.collections4.CollectionUtils
-import org.apache.commons.lang3.StringUtils
+import jakarta.servlet.http.HttpServletResponse
+import jakarta.ws.rs.core.MediaType
 import org.apache.juneau.html.HtmlSerializer
-import org.apache.juneau.http.annotation.Query
 import org.apache.juneau.json.JsonSerializer
 import org.apache.juneau.rest.RestRequest
 import org.apache.juneau.rest.RestResponse
 import org.apache.juneau.rest.annotation.Rest
 import org.apache.juneau.rest.annotation.RestGet
-import org.apache.juneau.rest.matcher.RestMatcher
 import org.apache.juneau.rest.servlet.BasicRestServlet
-import jakarta.ws.rs.core.MediaType
-import jakarta.servlet.http.HttpServletRequest
-import jakarta.servlet.http.HttpServletResponse
-import org.apache.http.client.utils.URIBuilder
-import org.apache.juneau.rest.httppart.RequestQueryParams
-import org.apache.streams.activitypub.api.pojo.Link
-import org.apache.streams.activitypub.api.pojo.Properties
+import org.apache.streams.activitypub.api.WebfingerApi
 import org.apache.streams.activitypub.api.pojo.WebfingerQueryRequest
 import org.apache.streams.activitypub.api.pojo.WebfingerQueryResponse
+import org.apache.streams.activitypub.graph.impl.WebfingerGraphImpl
 import org.apache.streams.activitypub.remote.WebfingerRest
-
-import java.util.ArrayList
-import java.net.URI
-import java.util.Optional
-import scala.collection.mutable.Buffer
-import scala.util.Try
+import org.apache.streams.activitypub.servlets.WebfingerServlet.webfinger
 
 /**
  * org.apache.streams.activitypub.servlets.WebfingerResource response to 
inquires about any URI, typically an item in one of the published feeds, or one 
of the
@@ -42,6 +30,11 @@ import scala.util.Try
  * as the default when no Accept is supplied, so that casual use through a
  */
 
+object WebfingerServlet {
+  given webfinger : WebfingerApi = WebfingerGraphImpl.DEFAULT
+
+}
+
 @Rest(
   title = Array("Webfinger Microservice"),
   description = Array("Webfinger Microservice"),
@@ -59,68 +52,47 @@ import scala.util.Try
 )
 class WebfingerServlet extends BasicRestServlet with WebfingerRest {
 
-    override def init(servletConfig: ServletConfig): Unit = {
-      super.init(servletConfig)
-    }
-
-//    class WebfingerAcceptMatcher extends RestMatcher {
-//
-//        private final val ACCEPTABLE = Set(
-//          "application/jrd+json",
-//          MediaType.APPLICATION_JSON,
-//          MediaType.TEXT_HTML
-//        )
-//
-//        def matches( httpServletRequest: HttpServletRequest ) : Boolean = {
-//            val acceptHeaderString: String = 
httpServletRequest.getHeader("Accept")
-//            val acceptHeaders = StringUtils.split(acceptHeaderString, 
',').toSet
-//            val matches = ACCEPTABLE.intersect(acceptHeaders).nonEmpty
-//            matches
-//        }
+  override def init(servletConfig: ServletConfig): Unit = {
+    super.init(servletConfig)
+  }
 
-//    }
-
-    def webfingerQueryRequestIsValid( request: WebfingerQueryRequest) : 
Boolean = {
-        !request.getResource().isEmpty()
-    }
+  def webfingerQueryRequestIsValid( request: WebfingerQueryRequest) : Boolean 
= {
+    !request.getResource().isEmpty()
+  }
 
-    @RestGet(
-            path = Array("/*"),
-            summary = "Lookup resources by URI",
-            description = Array("Lookup resources by URI"),
-            //matchers = Array(classOf[WebfingerAcceptMatcher])
-    )
-    def webfingerQueryGet(restRequest: RestRequest,
-                          restResponse: RestResponse ) = {
+  @RestGet(
+    path = Array("/*"),
+    summary = "Lookup resources by URI",
+    description = Array("Lookup resources by URI"),
+    //matchers = Array(classOf[WebfingerAcceptMatcher])
+  )
+  def webfingerQueryGet(restRequest: RestRequest,
+                        restResponse: RestResponse ) = {
 
-      val resource = restRequest.getParameter("resource")
+    val resource = restRequest.getParameter("resource")
 
-      val webfingerQueryRequest = new WebfingerQueryRequest()
-             .withResource(resource);
+    val webfingerQueryRequest = new WebfingerQueryRequest()
+      .withResource(resource);
 
-        if (webfingerQueryRequestIsValid(webfingerQueryRequest)) {
-            try {
-              restResponse.setContent(webfingerQuery(webfingerQueryRequest));
-              restResponse.setStatus(HttpServletResponse.SC_OK);
-            } catch {
-              case e : Exception => {
-                restResponse.setException(e);
-                
restResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-              }
-            }
-        } else {
-          restResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+    if (webfingerQueryRequestIsValid(webfingerQueryRequest)) {
+      try {
+        restResponse.setContent(webfingerQuery(webfingerQueryRequest));
+        restResponse.setStatus(HttpServletResponse.SC_OK);
+      } catch {
+        case e : Exception => {
+          restResponse.setException(e);
+          restResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
         }
-
+      }
+    } else {
+      restResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST);
     }
 
-    def webfingerQuery( request : WebfingerQueryRequest) : 
WebfingerQueryResponse = {
-        val response = new WebfingerQueryResponse()
-                .withSubject(request.getResource())
-                .withProperties(
-                        new Properties()
-                                .withAdditionalProperty("propertyKey", 
"propertyValue")
-                )
-        response;
-    }
+  }
+
+  def doWebfingerQuery( request : WebfingerQueryRequest )( using webfingerApi 
: WebfingerApi ) : WebfingerQueryResponse = {
+    webfingerApi.webfingerQuery(request);
+  }
+
+  override def webfingerQuery(request: WebfingerQueryRequest): 
WebfingerQueryResponse = doWebfingerQuery(request)
 }
diff --git a/streams-activitypub-api/pom.xml b/streams-activitypub-utils/pom.xml
similarity index 64%
copy from streams-activitypub-api/pom.xml
copy to streams-activitypub-utils/pom.xml
index a759d5f..51fcf92 100755
--- a/streams-activitypub-api/pom.xml
+++ b/streams-activitypub-utils/pom.xml
@@ -18,36 +18,34 @@
   -->
 
 <project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
-
-    <modelVersion>4.0.0</modelVersion>
-
     <parent>
         <artifactId>apache-streams-activitypub</artifactId>
         <groupId>org.apache.streams.activitypub</groupId>
         <version>0.8.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
+    <modelVersion>4.0.0</modelVersion>
 
-    <artifactId>streams-activitypub-api</artifactId>
-    <description>Apache Streams ActivityPub Server APIs</description>
+    <artifactId>streams-activitypub-utils</artifactId>
     <name>${project.artifactId}</name>
+
+    <description>Apache Streams Utility Classes</description>
+
     <packaging>jar</packaging>
 
     <dependencies>
-
         <dependency>
-            <groupId>org.apache.streams</groupId>
-            <artifactId>streams-config</artifactId>
-            <version>${project.version}</version>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>${httpcomponents.client.version}</version>
         </dependency>
-
-        <!-- streams-api only dependencies -->
+        <!-- streams-activitypub-utils only dependencies -->
         <dependency>
             <groupId>org.apache.juneau</groupId>
-            <artifactId>juneau-rest-common</artifactId>
+            <artifactId>juneau-marshall</artifactId>
             <version>${juneau.version}</version>
         </dependency>
-
+        <!-- streams-activitypub-utils only test dependencies -->
     </dependencies>
     <build>
         <sourceDirectory>src/main/scala</sourceDirectory>
@@ -64,38 +62,17 @@
         </testResources>
         <plugins>
             <plugin>
-                <groupId>net.alchim31.maven</groupId>
-                <artifactId>scala-maven-plugin</artifactId>
-                <configuration>
-                    <source>${project.basedir}/src/main/scala</source>
-                    <scalaVersion>${scala.version}</scalaVersion>
-                </configuration>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>compile</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.jsonschema2pojo</groupId>
-                <artifactId>jsonschema2pojo-maven-plugin</artifactId>
-                <version>1.2.1</version>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
                 <executions>
                     <execution>
-                        <id>generate-sources</id>
                         <goals>
-                            <goal>generate</goal>
+                            <goal>jar</goal>
+                            <goal>test-jar</goal>
                         </goals>
-                        <phase>generate-sources</phase>
                     </execution>
                 </executions>
             </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-jar-plugin</artifactId>
-            </plugin>
         </plugins>
     </build>
 </project>
diff --git 
a/streams-activitypub-utils/src/main/scala/org/apache/streams/activitypub/util/AcctPrefixResourceToResourceURISwap.scala
 
b/streams-activitypub-utils/src/main/scala/org/apache/streams/activitypub/util/AcctPrefixResourceToResourceURISwap.scala
new file mode 100644
index 0000000..4c30cce
--- /dev/null
+++ 
b/streams-activitypub-utils/src/main/scala/org/apache/streams/activitypub/util/AcctPrefixResourceToResourceURISwap.scala
@@ -0,0 +1,39 @@
+package org.apache.streams.activitypub.util
+
+import org.apache.http.client.utils.URIBuilder
+import org.apache.juneau.BeanSession
+import org.apache.juneau.ClassMeta
+import org.apache.juneau.swap.StringSwap
+
+import java.net.URI
+
+object AcctPrefixResourceToResourceURISwap {
+  def doSwap(uri: URI): String = {
+    val domain = uri.getHost
+    val preferredName = uri.getPath.split("/").last
+    s"acct:${preferredName}@${domain}"
+  }
+  def doUnswap(string: String): URI = {
+    val preferredName = string.split("@")(0)
+    val domain = string.split("@")(1)
+    val uriBuilder = new URIBuilder()
+      .setScheme("https")
+      .setHost(domain)
+      .setPath(s"/users/${preferredName}")
+    uriBuilder.build()
+  }
+}
+
+class AcctPrefixResourceToResourceURISwap extends StringSwap[URI] {
+
+  //@throws(classOf[Exception])
+  override def swap(session: BeanSession, uri: URI) : String = {
+    AcctPrefixResourceToResourceURISwap.doSwap(uri)
+  }
+
+  //@throws(classOf[Exception])
+  override def unswap(session: BeanSession, in: String, hint: ClassMeta[Any]): 
URI = {
+    AcctPrefixResourceToResourceURISwap.doUnswap(in);
+  }
+
+}
diff --git 
a/streams-activitypub-utils/src/test/scala/AcctPrefixResourceURISwapTest.scala 
b/streams-activitypub-utils/src/test/scala/AcctPrefixResourceURISwapTest.scala
new file mode 100644
index 0000000..2dbfc9f
--- /dev/null
+++ 
b/streams-activitypub-utils/src/test/scala/AcctPrefixResourceURISwapTest.scala
@@ -0,0 +1,34 @@
+package org.apache.streams.activitypub.util.test.cases
+
+import org.apache.http.client.utils.URIBuilder
+import org.apache.streams.activitypub.util.AcctPrefixResourceToResourceURISwap
+import org.junit.jupiter.api.Assertions
+import org.junit.jupiter.api.DisplayName
+import org.junit.jupiter.api.Test
+
+import java.net.URI
+
+class AcctPrefixResourceURISwapTest {
+
+  private final val swapper = new AcctPrefixResourceToResourceURISwap()
+
+  @Test
+  @DisplayName("Test Acct Prefix Swap")
+  def testSwap() = {
+    val testInput: URI = new URIBuilder()
+      .setScheme("https")
+      .setHost("mastodon.social")
+      .setPath("/users/steveblackmon")
+      .build()
+    val testOutput: String = "acct:steveblackmon@mastodon.social"
+    Assertions.assertEquals(testOutput, 
AcctPrefixResourceToResourceURISwap.doSwap(testInput))
+  }
+
+  @Test
+  @DisplayName("Test Acct Prefix Un-Swap")
+  def testUnswap() = {
+    val testInput: String = "acct:steveblackmon@mastodon.social"
+    val testOutput: URI = new 
URIBuilder("https://mastodon.social/users/steveblackmon";).build()
+    Assertions.assertEquals(testOutput, 
AcctPrefixResourceToResourceURISwap.doUnswap(testInput))
+  }
+}
diff --git a/streams-activitypub-webapp/pom.xml 
b/streams-activitypub-webapp/pom.xml
index 4fbdbed..fc4ca26 100755
--- a/streams-activitypub-webapp/pom.xml
+++ b/streams-activitypub-webapp/pom.xml
@@ -51,6 +51,11 @@
             <artifactId>streams-activitypub-actors</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.streams.activitypub</groupId>
+            <artifactId>streams-activitypub-graph</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.apache.streams.activitypub</groupId>
             <artifactId>streams-activitypub-servlets</artifactId>
@@ -68,6 +73,16 @@
 <!--            <version>${tomcat.version}</version>-->
 <!--            <scope>provided</scope>-->
 <!--        </dependency>-->
+
+        <!-- streams-activitypub-webapp test dependencies -->
+        <dependency>
+            <groupId>org.apache.streams.activitypub</groupId>
+            <artifactId>streams-activitypub-graph</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+            <type>test-jar</type>
+        </dependency>
+
         <dependency>
             <groupId>org.apache.tomcat.embed</groupId>
             <artifactId>tomcat-embed-core</artifactId>
@@ -104,6 +119,27 @@
             <version>${tomcat.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.jena</groupId>
+            <artifactId>jena-fuseki-main</artifactId>
+            <version>${jena.version}</version>
+            <type>jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.jena</groupId>
+            <artifactId>jena-arq</artifactId>
+            <version>${jena.version}</version>
+            <type>jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.jena</groupId>
+            <artifactId>jena-rdfconnection</artifactId>
+            <version>${jena.version}</version>
+            <type>jar</type>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <build>
         <finalName>streams-activitypub-webapp</finalName>
@@ -164,6 +200,30 @@
                     </webResources>
                 </configuration>
             </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-resources</id>
+                        <phase>process-test-resources</phase>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>
+                        <configuration>
+                            
<outputDirectory>${project.build.testOutputDirectory}</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>..</directory>
+                                    <includes>
+                                        <include>*.ttl</include>
+                                    </includes>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 </project>
diff --git a/streams-activitypub-webapp/src/test/resources/application.conf 
b/streams-activitypub-webapp/src/test/resources/application.conf
new file mode 100644
index 0000000..fde8a62
--- /dev/null
+++ b/streams-activitypub-webapp/src/test/resources/application.conf
@@ -0,0 +1,9 @@
+ActivityPubGraphTestSuiteExtensionConfig = {
+  fusekiEndpointURI = "http://localhost:13330/";
+  testDatasetResource = "doap.ttl"
+  testDatasetId = "doap.ttl"
+}
+WebfingerGraphImplConfig = {
+  fusekiEndpointURI = "http://localhost:13330/";
+  defaultDatasetId = "doap.ttl"
+}
diff --git 
a/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/ActivityPubWebappTestSuite.scala
 
b/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/ActivityPubWebappTestSuite.scala
index 87c736a..8efba57 100755
--- 
a/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/ActivityPubWebappTestSuite.scala
+++ 
b/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/ActivityPubWebappTestSuite.scala
@@ -1,6 +1,6 @@
 package org.apache.streams.activitypub.webapp.test
 
-import org.junit.jupiter.api.Order
+import 
org.apache.streams.activitypub.graph.test.ActivityPubGraphTestSuiteExtension
 import org.junit.jupiter.api.extension.RegisterExtension
 import org.junit.platform.suite.api.SelectClasses
 import org.junit.platform.suite.api.Suite
@@ -13,15 +13,18 @@ import org.junit.platform.suite.api.SuiteDisplayName;
 object ActivityPubWebappTestSuite {
 
   @RegisterExtension
-  val helper: ActivityPubWebappTestSuiteExtension = new 
ActivityPubWebappTestSuiteExtension()
+  given webapp: ActivityPubWebappTestSuiteExtension = new 
ActivityPubWebappTestSuiteExtension()
+
+  @RegisterExtension
+  given graph: ActivityPubGraphTestSuiteExtension = new 
ActivityPubGraphTestSuiteExtension()
 
 }
 
 @Suite
 @SuiteDisplayName("ActivityPub Webapp Integration Tests")
-@Order(Order.DEFAULT)
 @SelectClasses(Array(
-  
classOf[org.apache.streams.activitypub.webapp.test.cases.ServerAvailableTest],
+  
classOf[org.apache.streams.activitypub.graph.test.cases.GraphDatabaseServerAvailableTest],
+  
classOf[org.apache.streams.activitypub.webapp.test.cases.WebappServerAvailableTest],
   
classOf[org.apache.streams.activitypub.webapp.test.cases.ServletRegistrationTest],
   classOf[org.apache.streams.activitypub.webapp.test.cases.RootServletTest],
   
classOf[org.apache.streams.activitypub.webapp.test.cases.WebfingerServletTest]
diff --git 
a/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/ActivityPubWebappTestSuiteExtension.scala
 
b/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/ActivityPubWebappTestSuiteExtension.scala
index 40ce03b..1266955 100644
--- 
a/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/ActivityPubWebappTestSuiteExtension.scala
+++ 
b/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/ActivityPubWebappTestSuiteExtension.scala
@@ -1,10 +1,7 @@
 package org.apache.streams.activitypub.webapp.test
 
 import org.apache.catalina.Context
-import org.apache.catalina.Loader
 import org.apache.catalina.Server
-import org.apache.catalina.loader.WebappClassLoaderBase
-import org.apache.catalina.loader.WebappLoader
 import org.apache.catalina.startup.Tomcat
 import org.apache.http.client.utils.URIBuilder
 import org.apache.http.impl.NoConnectionReuseStrategy
@@ -17,11 +14,9 @@ import org.junit.jupiter.api.extension.ParameterResolver
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 
-import java.io.File
 import java.net.URI
 import java.nio.file.Path
 import java.nio.file.Paths
-import java.nio.file.Files
 
 class ActivityPubWebappTestSuiteExtension extends ParameterResolver with 
BeforeAllCallback with AfterAllCallback {
 
@@ -36,7 +31,7 @@ class ActivityPubWebappTestSuiteExtension extends 
ParameterResolver with BeforeA
     case "streams-activitypub-webapp" => Paths.get(basePathDir, 
"target/streams-activitypub-webapp")
   }
   private val webapp: String = webappPath.toAbsolutePath.toString
-  
+
   private val tomcat: Tomcat = new Tomcat()
   tomcat.enableNaming()
   tomcat.setBaseDir(basePathDir)
@@ -81,24 +76,13 @@ class ActivityPubWebappTestSuiteExtension extends 
ParameterResolver with BeforeA
 
   override def afterAll(extensionContext: ExtensionContext): Unit = {
     LOGGER.info("afterAll()")
-    try {
-      tomcat.stop();
-    } catch {
-      case e: Exception => LOGGER.error("Exception while stopping tomcat", e);
-    } finally {
-      try {
-        tomcat.destroy();
-      } catch {
-        case e: Exception => LOGGER.error("Exception while destoying tomcat", 
e);
-      }
-    }
   }
 
   override def supportsParameter(parameterContext: ParameterContext, 
extensionContext: ExtensionContext): Boolean = {
-    false
+    parameterContext.getParameter.getType.equals(this.getClass)
   }
 
   override def resolveParameter(parameterContext: ParameterContext, 
extensionContext: ExtensionContext): AnyRef = {
-    null
+    this
   }
 }
diff --git 
a/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/cases/RootServletTest.scala
 
b/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/cases/RootServletTest.scala
index f095b80..c57e3a3 100755
--- 
a/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/cases/RootServletTest.scala
+++ 
b/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/cases/RootServletTest.scala
@@ -3,19 +3,24 @@ package org.apache.streams.activitypub.webapp.test.cases
 import org.apache.streams.activitypub.webapp.test.ActivityPubWebappTestSuite
 import 
org.apache.streams.activitypub.webapp.test.ActivityPubWebappTestSuiteExtension
 import org.junit.jupiter.api.DisplayName
+import org.junit.jupiter.api.Order
 import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.extension.ExtendWith
-import org.slf4j.LoggerFactory;
+import org.slf4j.LoggerFactory
 
+@ExtendWith(Array(classOf[ActivityPubWebappTestSuiteExtension]))
 class RootServletTest {
 
     private final val LOGGER = 
LoggerFactory.getLogger(classOf[RootServletTest]);
 
-    @Test
+    /**
+     * Test that the root resource is available
+     */
     @DisplayName("Root Resource Available")
-    @throws(classOf[Exception])
-    def testRootResourceAvailable() : Unit = {
-        val response = 
ActivityPubWebappTestSuite.helper.restClient.get().json().run();
-        assert(response.getStatusCode() == 200);
+    @Order(2)
+    @Test
+    def testRootResourceAvailable(using helper : 
ActivityPubWebappTestSuiteExtension) : Unit = {
+        val response = helper.restClient.get().json().run();
+        assert(response.getStatusCode == 200);
     }
 }
diff --git 
a/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/cases/ServletRegistrationTest.scala
 
b/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/cases/ServletRegistrationTest.scala
index 538a50b..1ee50ee 100755
--- 
a/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/cases/ServletRegistrationTest.scala
+++ 
b/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/cases/ServletRegistrationTest.scala
@@ -1,23 +1,30 @@
 package org.apache.streams.activitypub.webapp.test.cases
 
-import org.apache.streams.activitypub.webapp.test.ActivityPubWebappTestSuite
+import 
org.apache.streams.activitypub.webapp.test.ActivityPubWebappTestSuiteExtension
 import org.junit.jupiter.api.Assertions
 import org.junit.jupiter.api.DisplayName
+import org.junit.jupiter.api.Order
 import org.junit.jupiter.api.Test
-import org.slf4j.LoggerFactory;
+import org.junit.jupiter.api.extension.ExtendWith
+import org.slf4j.LoggerFactory
 
+
+@ExtendWith(Array(classOf[ActivityPubWebappTestSuiteExtension]))
 class ServletRegistrationTest {
 
     private final val LOGGER = 
LoggerFactory.getLogger(classOf[ServletRegistrationTest]);
 
-    @Test
+    /**
+     * Tests that all servlets are registered
+     */
     @DisplayName("All Servlets are registered")
-    @throws(classOf[Exception])
-    def testAllServletsRegistered() : Unit = {
-        val servletRegistations = 
ActivityPubWebappTestSuite.helper.context.getServletContext.getServletRegistrations()
-        Assertions.assertNotNull(servletRegistations)
-        Assertions.assertEquals(2, servletRegistations.size())
-        Assertions.assertTrue(servletRegistations.containsKey("root"))
-        Assertions.assertTrue(servletRegistations.containsKey("webfinger"))
+    @Order(3)
+    @Test
+    def testAllServletsRegistered(using helper: 
ActivityPubWebappTestSuiteExtension) : Unit = {
+        val servletRegistrations = 
helper.context.getServletContext.getServletRegistrations()
+        Assertions.assertNotNull(servletRegistrations)
+        Assertions.assertEquals(2, servletRegistrations.size())
+        Assertions.assertTrue(servletRegistrations.containsKey("root"))
+        Assertions.assertTrue(servletRegistrations.containsKey("webfinger"))
     }
 }
diff --git 
a/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/cases/ServerAvailableTest.scala
 
b/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/cases/WebappServerAvailableTest.scala
similarity index 53%
rename from 
streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/cases/ServerAvailableTest.scala
rename to 
streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/cases/WebappServerAvailableTest.scala
index 8eedc05..a2af02c 100755
--- 
a/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/cases/ServerAvailableTest.scala
+++ 
b/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/cases/WebappServerAvailableTest.scala
@@ -1,31 +1,33 @@
 package org.apache.streams.activitypub.webapp.test.cases
 
+import 
org.apache.streams.activitypub.webapp.test.ActivityPubWebappTestSuiteExtension
 import org.awaitility.Awaitility.await
-import org.awaitility.Awaitility.waitAtMost
-import org.awaitility.core.ConditionTimeoutException
-import org.apache.streams.activitypub.webapp.test.ActivityPubWebappTestSuite
 import org.awaitility.scala.AwaitilitySupport
-import org.hamcrest.MatcherAssert.assertThat
 import org.junit.jupiter.api.Assertions
 import org.junit.jupiter.api.DisplayName
+import org.junit.jupiter.api.Order
 import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
 import org.slf4j.LoggerFactory
 
 import scala.concurrent.duration.MINUTES
-import scala.concurrent.duration.SECONDS
 import scala.util.Try;
 
-class ServerAvailableTest extends AwaitilitySupport {
+@ExtendWith(Array(classOf[ActivityPubWebappTestSuiteExtension]))
+class WebappServerAvailableTest extends AwaitilitySupport {
 
-    private final val LOGGER = 
LoggerFactory.getLogger(classOf[ServerAvailableTest]);
+    private final val LOGGER = 
LoggerFactory.getLogger(classOf[WebappServerAvailableTest]);
 
-    @Test
+    /**
+     * Test that the server is available
+     */
     @DisplayName("Test server is available")
-    @throws(classOf[Exception])
-    def testServerAvailable() : Unit = {
+    @Order(0)
+    @Test
+    def testWebappServerAvailable(using helper: 
ActivityPubWebappTestSuiteExtension) : Unit = {
         val testAttempt = Try {
             await atMost(5, MINUTES) untilAsserted {
-                
ActivityPubWebappTestSuite.helper.server.getStateName.matches("STARTED")
+                helper.server.getStateName.matches("STARTED")
             }
         }
         Assertions.assertTrue(testAttempt.isSuccess)
diff --git 
a/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/cases/WebfingerServletTest.scala
 
b/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/cases/WebfingerServletTest.scala
index 2436980..65a8c86 100755
--- 
a/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/cases/WebfingerServletTest.scala
+++ 
b/streams-activitypub-webapp/src/test/scala/org/apache/streams/activitypub/webapp/test/cases/WebfingerServletTest.scala
@@ -3,36 +3,53 @@ package org.apache.streams.activitypub.webapp.test.cases
 import org.apache.http.HttpStatus
 import org.apache.http.client.utils.URIBuilder
 import org.apache.http.entity.ContentType
-import org.apache.juneau.rest.client.RestResponse
-import org.apache.streams.activitypub.webapp.test.ActivityPubWebappTestSuite
 import 
org.apache.streams.activitypub.webapp.test.ActivityPubWebappTestSuiteExtension
 import org.junit.jupiter.api.DisplayName
+import org.junit.jupiter.api.Order
 import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.extension.ExtendWith
-import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 
 import java.nio.charset.Charset;
 
-class WebfingerServletTest {
+@ExtendWith(Array(classOf[ActivityPubWebappTestSuiteExtension]))
+class WebfingerServletTest(using helper: ActivityPubWebappTestSuiteExtension) {
 
     private final val LOGGER = 
LoggerFactory.getLogger(classOf[WebfingerServletTest]);
 
-    private val uriBuilder : URIBuilder = 
ActivityPubWebappTestSuite.helper.uriBuilder
+    private val uriBuilder : URIBuilder = helper.uriBuilder
       .setCharset(Charset.defaultCharset())
       .setPath(".well-known/webfinger")
 
-    @Test
+    /**
+     * Test the WebfingerServlet with a valid abbreviated-form esource 
parameter
+     */
     @DisplayName("WebfingerQuery With Abbreviated Resource Parameter")
-    @throws(classOf[Exception])
-    def testWebfingerQueryWithAbbreviatedResourceParameter() : Unit = {
-        val request = ActivityPubWebappTestSuite.helper.restClientBuilder
-          .accept(ContentType.APPLICATION_JSON.getMimeType)  
+    @Order(4)
+    @Test
+    def testWebfingerQueryWithAbbreviatedResourceParameter(using helper: 
ActivityPubWebappTestSuiteExtension) : Unit = {
+        val request = helper.restClientBuilder
+          .accept(ContentType.APPLICATION_JSON.getMimeType)
+          .json()
+          .build()
+          .get(uriBuilder.setParameter("resource", 
"acct:steveblackmon@mastodon.social").build())
+        val response = request.run();
+        response.assertStatus(HttpStatus.SC_OK)
+    }
+
+    /**
+     * Test the WebfingerServlet with a valid URI-form resource parameter
+      */
+    @DisplayName("WebfingerQuery With URI Resource Parameter")
+    @Order(4)
+    @Test
+    def testWebfingerQueryWithUriResourceParameter(using helper: 
ActivityPubWebappTestSuiteExtension): Unit = {
+        val request = helper.restClientBuilder
+          .accept(ContentType.APPLICATION_JSON.getMimeType)
           .json()
           .build()
-          .get(uriBuilder.setParameter("resource", 
"acct:sblackmon@asf.social").build())
+          .get(uriBuilder.setParameter("resource", 
"https://mastodon.social/users/steveblackmon";).build())
         val response = request.run();
         response.assertStatus(HttpStatus.SC_OK)
     }
 }
-            

Reply via email to