diff --git a/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessGrantClient.java b/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessGrantClient.java index 538bb128e44..459dd4b8669 100644 --- a/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessGrantClient.java +++ b/access-grant/src/main/java/com/inrupt/client/accessgrant/AccessGrantClient.java @@ -65,7 +65,6 @@ * {@link Session} object, typically an OpenID-based session: * *
{@code
-   URI SOLID_ACCESS_GRANT = URI.create("http://www.w3.org/ns/solid/vc#SolidAccessGrant");
    URI issuer = URI.create("https://issuer.example");
    Session openid = OpenIdSession.ofIdToken(idToken);
 
@@ -73,7 +72,7 @@
 
    URI resource = URI.create("https://storage.example/data/resource");
    URI purpose = URI.create("https://purpose.example/1");
-   client.query(null, resource, purpose, "Read", AccessGrant.class)
+   client.query(resource, null, openid.getPrincipal().orElse(null), purpose, "Read", AccessGrant.class)
        .thenApply(grants -> AccessGrantSession.ofAccessGrant(openid, grants.toArray(new AccessGrant[0])))
        .thenApply(session -> SolidClient.getClient().session(session))
        .thenAccept(cl -> {
@@ -89,6 +88,7 @@ public class AccessGrantClient {
     private static final String VC_CONTEXT_URI = "https://www.w3.org/2018/credentials/v1";
     private static final String INRUPT_CONTEXT_URI = "https://schema.inrupt.com/credentials/v1.jsonld";
     private static final String VERIFIABLE_CREDENTIAL = "verifiableCredential";
+    private static final String SOLID_VC_NAMESPACE = "http://www.w3.org/ns/solid/vc#";
     private static final String TYPE = "type";
     private static final String APPLICATION_JSON = "application/json";
     private static final String CONTENT_TYPE = "Content-Type";
@@ -102,9 +102,12 @@ public class AccessGrantClient {
     private static final String FOR_PURPOSE = "forPurpose";
     private static final String EXPIRATION_DATE = "expirationDate";
     private static final String CREDENTIAL = "credential";
-    private static final URI ACCESS_GRANT = URI.create("http://www.w3.org/ns/solid/vc#SolidAccessGrant");
-    private static final URI ACCESS_REQUEST = URI.create("http://www.w3.org/ns/solid/vc#SolidAccessRequest");
-    private static final URI ACCESS_DENIAL = URI.create("http://www.w3.org/ns/solid/vc#SolidAccessDenial");
+    private static final String SOLID_ACCESS_GRANT = "SolidAccessGrant";
+    private static final String SOLID_ACCESS_REQUEST = "SolidAccessRequest";
+    private static final String SOLID_ACCESS_DENIAL = "SolidAccessDenial";
+    private static final URI FQ_ACCESS_GRANT = URI.create(SOLID_VC_NAMESPACE + SOLID_ACCESS_GRANT);
+    private static final URI FQ_ACCESS_REQUEST = URI.create(SOLID_VC_NAMESPACE + SOLID_ACCESS_REQUEST);
+    private static final URI FQ_ACCESS_DENIAL = URI.create(SOLID_VC_NAMESPACE + SOLID_ACCESS_DENIAL);
     private static final Set ACCESS_GRANT_TYPES = getAccessGrantTypes();
     private static final Set ACCESS_REQUEST_TYPES = getAccessRequestTypes();
     private static final Set ACCESS_DENIAL_TYPES = getAccessDenialTypes();
@@ -301,9 +304,9 @@ public CompletionStage issue(final URI type, final URI agent, final
         }
         return v1Metadata().thenCompose(metadata -> {
             final Map data;
-            if (ACCESS_GRANT.equals(type)) {
+            if (FQ_ACCESS_GRANT.equals(type)) {
                 data = buildAccessGrantv1(agent, resources, modes, expiration, uriPurposes);
-            } else if (ACCESS_REQUEST.equals(type)) {
+            } else if (FQ_ACCESS_REQUEST.equals(type)) {
                 data = buildAccessRequestv1(agent, resources, modes, expiration, uriPurposes);
             } else {
                 throw new AccessGrantException("Unsupported grant type: " + type);
@@ -377,27 +380,28 @@ public CompletionStage verify(final AccessCredenti
      * Perform an Access Grant query.
      *
      * @param  the AccessCredential type
-     * @param agent the agent identifier, may be {@code null}
      * @param resource the resource identifier, may be {@code null}
+     * @param creator the identifier for the agent who created the credential, may be {@code null}
+     * @param recipient the identifier for the agent who is the recipient for the credential, may be {@code null}
      * @param purpose the access purpose, may be {@code null}
      * @param mode the access mode, may be {@code null}
      * @param clazz the AccessCredential type, either {@link AccessGrant} or {@link AccessRequest}
-     * @return the next stage of completion, including the matched Access Grants
+     * @return the next stage of completion, including the matched Access Credentials
      */
-    public  CompletionStage> query(final URI agent, final URI resource,
-            final URI purpose, final String mode, final Class clazz) {
+    public  CompletionStage> query(final URI resource, final URI creator,
+            final URI recipient, final URI purpose, final String mode, final Class clazz) {
         Objects.requireNonNull(clazz, "The clazz parameter must not be null!");
 
         final URI type;
         final Set supportedTypes;
         if (AccessGrant.class.isAssignableFrom(clazz)) {
-            type = URI.create("SolidAccessGrant");
+            type = URI.create(SOLID_ACCESS_GRANT);
             supportedTypes = ACCESS_GRANT_TYPES;
         } else if (AccessRequest.class.isAssignableFrom(clazz)) {
-            type = URI.create("SolidAccessRequest");
+            type = URI.create(SOLID_ACCESS_REQUEST);
             supportedTypes = ACCESS_REQUEST_TYPES;
         } else if (AccessDenial.class.isAssignableFrom(clazz)) {
-            type = URI.create("SolidAccessDenial");
+            type = URI.create(SOLID_ACCESS_DENIAL);
             supportedTypes = ACCESS_DENIAL_TYPES;
         } else {
             throw new AccessGrantException("Unsupported type " + clazz + " in query request");
@@ -405,7 +409,7 @@ public  CompletionStage> query(final URI age
 
         return v1Metadata().thenCompose(metadata -> {
             final List>> futures = buildQuery(config.getIssuer(), type,
-                    agent, resource, purpose, mode).stream()
+                    resource, creator, recipient, purpose, mode).stream()
                 .map(data -> Request.newBuilder(metadata.queryEndpoint)
                         .header(CONTENT_TYPE, APPLICATION_JSON)
                         .POST(Request.BodyPublishers.ofByteArray(serialize(data))).build())
@@ -451,7 +455,7 @@ public CompletionStage> query(final URI type, final URI agent,
         Objects.requireNonNull(type, "The type parameter must not be null!");
         return v1Metadata().thenCompose(metadata -> {
             final List>> futures = buildQuery(config.getIssuer(), type,
-                    agent, resource, null, mode).stream()
+                    resource, null, agent, null, mode).stream()
                 .map(data -> Request.newBuilder(metadata.queryEndpoint)
                         .header(CONTENT_TYPE, APPLICATION_JSON)
                         .POST(Request.BodyPublishers.ofByteArray(serialize(data))).build())
@@ -683,26 +687,26 @@ static Collection getCredentials(final Map data) {
         return Collections.emptyList();
     }
 
-    static List> buildQuery(final URI issuer, final URI type, final URI agent, final URI resource,
-            final URI purpose, final String mode) {
+    static List> buildQuery(final URI issuer, final URI type, final URI resource, final URI creator,
+            final URI recipient, final URI purpose, final String mode) {
         final List> queries = new ArrayList<>();
-        buildQuery(queries, issuer, type, agent, resource, purpose, mode);
+        buildQuery(queries, issuer, type, resource, creator, recipient, purpose, mode);
         return queries;
     }
 
-    static void buildQuery(final List> queries, final URI issuer, final URI type, final URI agent,
-            final URI resource, final URI purpose, final String mode) {
+    static void buildQuery(final List> queries, final URI issuer, final URI type,
+            final URI resource, final URI creator, final URI recipient, final URI purpose, final String mode) {
         final Map credential = new HashMap<>();
         credential.put(CONTEXT, Arrays.asList(VC_CONTEXT_URI, INRUPT_CONTEXT_URI));
         credential.put("issuer", issuer);
         credential.put(TYPE, Arrays.asList(type));
 
         final Map consent = new HashMap<>();
-        if (agent != null) {
+        if (recipient != null) {
             if (isAccessGrant(type) || isAccessDenial(type)) {
-                consent.put(IS_PROVIDED_TO, agent);
+                consent.put(IS_PROVIDED_TO, recipient);
             } else if (isAccessRequest(type)) {
-                consent.put(IS_CONSENT_FOR_DATA_SUBJECT, agent);
+                consent.put(IS_CONSENT_FOR_DATA_SUBJECT, recipient);
             }
         }
         if (resource != null) {
@@ -716,6 +720,9 @@ static void buildQuery(final List> queries, final URI issuer
         }
 
         final Map subject = new HashMap<>();
+        if (creator != null) {
+            subject.put("id", creator);
+        }
         if (!consent.isEmpty()) {
             if (isAccessGrant(type) || isAccessDenial(type)) {
                 subject.put(PROVIDED_CONSENT, consent);
@@ -723,6 +730,8 @@ static void buildQuery(final List> queries, final URI issuer
                 subject.put("hasConsent", consent);
             }
             credential.put(CREDENTIAL_SUBJECT, subject);
+        } else if (!subject.isEmpty()) {
+            credential.put(CREDENTIAL_SUBJECT, subject);
         }
 
         final Map data = new HashMap<>();
@@ -733,7 +742,7 @@ static void buildQuery(final List> queries, final URI issuer
         // Recurse
         final URI parent = getParent(resource);
         if (parent != null) {
-            buildQuery(queries, issuer, type, agent, parent, purpose, mode);
+            buildQuery(queries, issuer, type, parent, creator, recipient, purpose, mode);
         }
     }
 
@@ -849,35 +858,35 @@ static boolean isSuccess(final int statusCode) {
 
     static Set getAccessRequestTypes() {
         final Set types = new HashSet<>();
-        types.add("SolidAccessRequest");
-        types.add(ACCESS_REQUEST.toString());
+        types.add(SOLID_ACCESS_REQUEST);
+        types.add(FQ_ACCESS_REQUEST.toString());
         return Collections.unmodifiableSet(types);
     }
 
     static Set getAccessGrantTypes() {
         final Set types = new HashSet<>();
-        types.add("SolidAccessGrant");
-        types.add(ACCESS_GRANT.toString());
+        types.add(SOLID_ACCESS_GRANT);
+        types.add(FQ_ACCESS_GRANT.toString());
         return Collections.unmodifiableSet(types);
     }
 
     static Set getAccessDenialTypes() {
         final Set types = new HashSet<>();
-        types.add("SolidAccessDenial");
-        types.add(ACCESS_DENIAL.toString());
+        types.add(SOLID_ACCESS_DENIAL);
+        types.add(FQ_ACCESS_DENIAL.toString());
         return Collections.unmodifiableSet(types);
     }
 
     static boolean isAccessGrant(final URI type) {
-        return "SolidAccessGrant".equals(type.toString()) || ACCESS_GRANT.equals(type);
+        return SOLID_ACCESS_GRANT.equals(type.toString()) || FQ_ACCESS_GRANT.equals(type);
     }
 
     static boolean isAccessRequest(final URI type) {
-        return "SolidAccessRequest".equals(type.toString()) || ACCESS_REQUEST.equals(type);
+        return SOLID_ACCESS_REQUEST.equals(type.toString()) || FQ_ACCESS_REQUEST.equals(type);
     }
 
     static boolean isAccessDenial(final URI type) {
-        return "SolidAccessDenial".equals(type.toString()) || ACCESS_DENIAL.equals(type);
+        return SOLID_ACCESS_DENIAL.equals(type.toString()) || FQ_ACCESS_DENIAL.equals(type);
     }
 
     /**
diff --git a/access-grant/src/test/java/com/inrupt/client/accessgrant/AccessGrantClientTest.java b/access-grant/src/test/java/com/inrupt/client/accessgrant/AccessGrantClientTest.java
index 05c5664dd4a..8757a8be196 100644
--- a/access-grant/src/test/java/com/inrupt/client/accessgrant/AccessGrantClientTest.java
+++ b/access-grant/src/test/java/com/inrupt/client/accessgrant/AccessGrantClientTest.java
@@ -508,9 +508,8 @@ void testQueryGrant() {
         final String token = generateIdToken(claims);
         final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token));
 
-        final List grants = client.query(null,
-                URI.create("https://storage.example/e973cc3d-5c28-4a10-98c5-e40079289358/a/b/c"), null, "Read",
-                AccessGrant.class)
+        final URI resource = URI.create("https://storage.example/e973cc3d-5c28-4a10-98c5-e40079289358/a/b/c");
+        final List grants = client.query(resource, null, null, null, "Read", AccessGrant.class)
                     .toCompletableFuture().join();
         assertEquals(1, grants.size());
     }
@@ -525,9 +524,8 @@ void testQueryGrantAgent() {
         final String token = generateIdToken(claims);
         final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token));
 
-        final List grants = client.query(URI.create("https://id.test/user"),
-                null, null, "Read", AccessGrant.class)
-                    .toCompletableFuture().join();
+        final List grants = client.query(null, null, URI.create("https://id.test/user"),
+                null, "Read", AccessGrant.class).toCompletableFuture().join();
         assertEquals(1, grants.size());
     }
 
@@ -541,9 +539,8 @@ void testQueryRequestAgent() {
         final String token = generateIdToken(claims);
         final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token));
 
-        final List requests = client.query(URI.create("https://id.test/user"),
-                null, null, "Read", AccessRequest.class)
-                    .toCompletableFuture().join();
+        final List requests = client.query(null, null, URI.create("https://id.test/user"),
+                null, "Read", AccessRequest.class).toCompletableFuture().join();
         assertEquals(1, requests.size());
     }
 
@@ -557,10 +554,9 @@ void testQueryRequest() {
         final String token = generateIdToken(claims);
         final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token));
 
-        final List requests = client.query(null,
-                URI.create("https://storage.example/f1759e6d-4dda-4401-be61-d90d070a5474/a/b/c"), null, "Read",
-                AccessRequest.class)
-                    .toCompletableFuture().join();
+        final URI resource = URI.create("https://storage.example/f1759e6d-4dda-4401-be61-d90d070a5474/a/b/c");
+        final List requests = client.query(resource, null, null, null, "Read", AccessRequest.class)
+            .toCompletableFuture().join();
         assertEquals(1, requests.size());
     }
 
@@ -574,10 +570,9 @@ void testQueryDenial() {
         final String token = generateIdToken(claims);
         final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token));
 
-        final List grants = client.query(null,
-                URI.create("https://storage.example/ef9c4b90-0459-408d-bfa9-1c61d46e1eaf/e/f/g"), null, "Read",
-                AccessDenial.class)
-                    .toCompletableFuture().join();
+        final URI resource = URI.create("https://storage.example/ef9c4b90-0459-408d-bfa9-1c61d46e1eaf/e/f/g");
+        final List grants = client.query(resource, null, null, null, "Read", AccessDenial.class)
+            .toCompletableFuture().join();
         assertEquals(1, grants.size());
     }
 
@@ -592,7 +587,8 @@ void testQueryInvalidType() {
         final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token));
 
         final URI uri = URI.create("https://storage.example/f1759e6d-4dda-4401-be61-d90d070a5474/a/b/c");
-        assertThrows(AccessGrantException.class, () -> client.query(null, uri, null, "Read", AccessCredential.class));
+        assertThrows(AccessGrantException.class, () ->
+                client.query(uri, null, null, null, "Read", AccessCredential.class));
     }
 
 
diff --git a/integration/base/src/main/java/com/inrupt/client/integration/base/AccessGrantScenarios.java b/integration/base/src/main/java/com/inrupt/client/integration/base/AccessGrantScenarios.java
index 7c57a1136f0..cdb352f06f6 100644
--- a/integration/base/src/main/java/com/inrupt/client/integration/base/AccessGrantScenarios.java
+++ b/integration/base/src/main/java/com/inrupt/client/integration/base/AccessGrantScenarios.java
@@ -323,8 +323,8 @@ void accessGrantQueryByRequestorTest(final Session session) {
         final AccessGrantClient accessGrantClient = new AccessGrantClient(URI.create(VC_PROVIDER)).session(session);
 
         //query for all grants issued by the user
-        final List grants = accessGrantClient.query(URI.create(webidUrl),
-                sharedResource, PURPOSE1, GRANT_MODE_READ, AccessRequest.class)
+        final List grants = accessGrantClient.query(sharedResource, null, URI.create(webidUrl),
+                PURPOSE1, GRANT_MODE_READ, AccessRequest.class)
             .toCompletableFuture().join();
         // result is 4 because we retrieve the grants for each path
         // sharedTextFileURI =
@@ -332,8 +332,8 @@ void accessGrantQueryByRequestorTest(final Session session) {
         assertEquals(1, grants.size());
 
         //query for all grants issued by a random user
-        final List randomGrants = accessGrantClient.query(URI.create("https://someuser.test"),
-                sharedResource, PURPOSE1, GRANT_MODE_READ, AccessRequest.class)
+        final List randomGrants = accessGrantClient.query(sharedResource, null,
+                URI.create("https://someuser.test"), PURPOSE1, GRANT_MODE_READ, AccessRequest.class)
             .toCompletableFuture().join();
         assertEquals(0, randomGrants.size());
     }
@@ -347,14 +347,14 @@ void accessGrantQueryByResourceTest(final Session session) {
         final AccessGrantClient accessGrantClient = new AccessGrantClient(URI.create(VC_PROVIDER)).session(session);
 
         //query for all grants of a dedicated resource
-        final List requests = accessGrantClient.query(URI.create(webidUrl),
-                sharedResource, PURPOSE1, GRANT_MODE_READ, AccessRequest.class)
+        final List requests = accessGrantClient.query(sharedResource, null, URI.create(webidUrl),
+                PURPOSE1, GRANT_MODE_READ, AccessRequest.class)
             .toCompletableFuture().join();
         assertEquals(1, requests.size());
 
         //query for all grants of a random resource
-        final List randomGrants = accessGrantClient.query(URI.create(webidUrl),
-                URI.create("https://somerandom.test"), PURPOSE1, GRANT_MODE_READ, AccessRequest.class)
+        final List randomGrants = accessGrantClient.query(URI.create("https://somerandom.test"),
+                null, URI.create(webidUrl), PURPOSE1, GRANT_MODE_READ, AccessRequest.class)
             .toCompletableFuture().join();
         assertEquals(0, randomGrants.size());
     }
@@ -368,14 +368,14 @@ void accessGrantQueryByPurposeTest(final Session session) {
         final AccessGrantClient accessGrantClient = new AccessGrantClient(URI.create(VC_PROVIDER)).session(session);
 
         //query for all grants with a dedicated purpose
-        final List requests = accessGrantClient.query(URI.create(webidUrl),
-                sharedResource, PURPOSE1, GRANT_MODE_READ, AccessRequest.class)
+        final List requests = accessGrantClient.query(sharedResource, null, URI.create(webidUrl),
+                PURPOSE1, GRANT_MODE_READ, AccessRequest.class)
             .toCompletableFuture().join();
         assertEquals(1, requests.size());
 
         //query for all grants of dedicated purpose combinations
-        final List randomGrants = accessGrantClient.query(URI.create(webidUrl),
-                sharedResource, PURPOSE1, GRANT_MODE_WRITE, AccessGrant.class)
+        final List randomGrants = accessGrantClient.query(sharedResource, null, URI.create(webidUrl),
+                PURPOSE1, GRANT_MODE_WRITE, AccessGrant.class)
             .toCompletableFuture().join();
         assertEquals(0, randomGrants.size()); //our grant is actually a Read
     }