6565 * {@link Session} object, typically an OpenID-based session:
6666 *
6767 * <pre>{@code
68- URI SOLID_ACCESS_GRANT = URI.create("http://www.w3.org/ns/solid/vc#SolidAccessGrant");
6968 URI issuer = URI.create("https://issuer.example");
7069 Session openid = OpenIdSession.ofIdToken(idToken);
7170
7271 AccessGrantClient client = new AccessGrantClient(issuer).session(session);
7372
7473 URI resource = URI.create("https://storage.example/data/resource");
7574 URI purpose = URI.create("https://purpose.example/1");
76- client.query(null, resource , purpose, "Read", AccessGrant.class)
75+ client.query(resource, null, openid.getPrincipal().orElse(null) , purpose, "Read", AccessGrant.class)
7776 .thenApply(grants -> AccessGrantSession.ofAccessGrant(openid, grants.toArray(new AccessGrant[0])))
7877 .thenApply(session -> SolidClient.getClient().session(session))
7978 .thenAccept(cl -> {
@@ -89,6 +88,7 @@ public class AccessGrantClient {
8988 private static final String VC_CONTEXT_URI = "https://www.w3.org/2018/credentials/v1" ;
9089 private static final String INRUPT_CONTEXT_URI = "https://schema.inrupt.com/credentials/v1.jsonld" ;
9190 private static final String VERIFIABLE_CREDENTIAL = "verifiableCredential" ;
91+ private static final String SOLID_VC_NAMESPACE = "http://www.w3.org/ns/solid/vc#" ;
9292 private static final String TYPE = "type" ;
9393 private static final String APPLICATION_JSON = "application/json" ;
9494 private static final String CONTENT_TYPE = "Content-Type" ;
@@ -102,9 +102,12 @@ public class AccessGrantClient {
102102 private static final String FOR_PURPOSE = "forPurpose" ;
103103 private static final String EXPIRATION_DATE = "expirationDate" ;
104104 private static final String CREDENTIAL = "credential" ;
105- private static final URI ACCESS_GRANT = URI .create ("http://www.w3.org/ns/solid/vc#SolidAccessGrant" );
106- private static final URI ACCESS_REQUEST = URI .create ("http://www.w3.org/ns/solid/vc#SolidAccessRequest" );
107- private static final URI ACCESS_DENIAL = URI .create ("http://www.w3.org/ns/solid/vc#SolidAccessDenial" );
105+ private static final String SOLID_ACCESS_GRANT = "SolidAccessGrant" ;
106+ private static final String SOLID_ACCESS_REQUEST = "SolidAccessRequest" ;
107+ private static final String SOLID_ACCESS_DENIAL = "SolidAccessDenial" ;
108+ private static final URI FQ_ACCESS_GRANT = URI .create (SOLID_VC_NAMESPACE + SOLID_ACCESS_GRANT );
109+ private static final URI FQ_ACCESS_REQUEST = URI .create (SOLID_VC_NAMESPACE + SOLID_ACCESS_REQUEST );
110+ private static final URI FQ_ACCESS_DENIAL = URI .create (SOLID_VC_NAMESPACE + SOLID_ACCESS_DENIAL );
108111 private static final Set <String > ACCESS_GRANT_TYPES = getAccessGrantTypes ();
109112 private static final Set <String > ACCESS_REQUEST_TYPES = getAccessRequestTypes ();
110113 private static final Set <String > ACCESS_DENIAL_TYPES = getAccessDenialTypes ();
@@ -301,9 +304,9 @@ public CompletionStage<AccessGrant> issue(final URI type, final URI agent, final
301304 }
302305 return v1Metadata ().thenCompose (metadata -> {
303306 final Map <String , Object > data ;
304- if (ACCESS_GRANT .equals (type )) {
307+ if (FQ_ACCESS_GRANT .equals (type )) {
305308 data = buildAccessGrantv1 (agent , resources , modes , expiration , uriPurposes );
306- } else if (ACCESS_REQUEST .equals (type )) {
309+ } else if (FQ_ACCESS_REQUEST .equals (type )) {
307310 data = buildAccessRequestv1 (agent , resources , modes , expiration , uriPurposes );
308311 } else {
309312 throw new AccessGrantException ("Unsupported grant type: " + type );
@@ -377,35 +380,36 @@ public CompletionStage<AccessCredentialVerification> verify(final AccessCredenti
377380 * Perform an Access Grant query.
378381 *
379382 * @param <T> the AccessCredential type
380- * @param agent the agent identifier, may be {@code null}
381383 * @param resource the resource identifier, may be {@code null}
384+ * @param creator the identifier for the agent who created the credential, may be {@code null}
385+ * @param recipient the identifier for the agent who is the recipient for the credential, may be {@code null}
382386 * @param purpose the access purpose, may be {@code null}
383387 * @param mode the access mode, may be {@code null}
384388 * @param clazz the AccessCredential type, either {@link AccessGrant} or {@link AccessRequest}
385- * @return the next stage of completion, including the matched Access Grants
389+ * @return the next stage of completion, including the matched Access Credentials
386390 */
387- public <T extends AccessCredential > CompletionStage <List <T >> query (final URI agent , final URI resource ,
388- final URI purpose , final String mode , final Class <T > clazz ) {
391+ public <T extends AccessCredential > CompletionStage <List <T >> query (final URI resource , final URI creator ,
392+ final URI recipient , final URI purpose , final String mode , final Class <T > clazz ) {
389393 Objects .requireNonNull (clazz , "The clazz parameter must not be null!" );
390394
391395 final URI type ;
392396 final Set <String > supportedTypes ;
393397 if (AccessGrant .class .isAssignableFrom (clazz )) {
394- type = URI .create ("SolidAccessGrant" );
398+ type = URI .create (SOLID_ACCESS_GRANT );
395399 supportedTypes = ACCESS_GRANT_TYPES ;
396400 } else if (AccessRequest .class .isAssignableFrom (clazz )) {
397- type = URI .create ("SolidAccessRequest" );
401+ type = URI .create (SOLID_ACCESS_REQUEST );
398402 supportedTypes = ACCESS_REQUEST_TYPES ;
399403 } else if (AccessDenial .class .isAssignableFrom (clazz )) {
400- type = URI .create ("SolidAccessDenial" );
404+ type = URI .create (SOLID_ACCESS_DENIAL );
401405 supportedTypes = ACCESS_DENIAL_TYPES ;
402406 } else {
403407 throw new AccessGrantException ("Unsupported type " + clazz + " in query request" );
404408 }
405409
406410 return v1Metadata ().thenCompose (metadata -> {
407411 final List <CompletableFuture <List <T >>> futures = buildQuery (config .getIssuer (), type ,
408- agent , resource , purpose , mode ).stream ()
412+ resource , creator , recipient , purpose , mode ).stream ()
409413 .map (data -> Request .newBuilder (metadata .queryEndpoint )
410414 .header (CONTENT_TYPE , APPLICATION_JSON )
411415 .POST (Request .BodyPublishers .ofByteArray (serialize (data ))).build ())
@@ -451,7 +455,7 @@ public CompletionStage<List<AccessGrant>> query(final URI type, final URI agent,
451455 Objects .requireNonNull (type , "The type parameter must not be null!" );
452456 return v1Metadata ().thenCompose (metadata -> {
453457 final List <CompletableFuture <List <AccessGrant >>> futures = buildQuery (config .getIssuer (), type ,
454- agent , resource , null , mode ).stream ()
458+ resource , null , agent , null , mode ).stream ()
455459 .map (data -> Request .newBuilder (metadata .queryEndpoint )
456460 .header (CONTENT_TYPE , APPLICATION_JSON )
457461 .POST (Request .BodyPublishers .ofByteArray (serialize (data ))).build ())
@@ -683,26 +687,26 @@ static Collection<Object> getCredentials(final Map<String, Object> data) {
683687 return Collections .emptyList ();
684688 }
685689
686- static List <Map <String , Object >> buildQuery (final URI issuer , final URI type , final URI agent , final URI resource ,
687- final URI purpose , final String mode ) {
690+ static List <Map <String , Object >> buildQuery (final URI issuer , final URI type , final URI resource , final URI creator ,
691+ final URI recipient , final URI purpose , final String mode ) {
688692 final List <Map <String , Object >> queries = new ArrayList <>();
689- buildQuery (queries , issuer , type , agent , resource , purpose , mode );
693+ buildQuery (queries , issuer , type , resource , creator , recipient , purpose , mode );
690694 return queries ;
691695 }
692696
693- static void buildQuery (final List <Map <String , Object >> queries , final URI issuer , final URI type , final URI agent ,
694- final URI resource , final URI purpose , final String mode ) {
697+ static void buildQuery (final List <Map <String , Object >> queries , final URI issuer , final URI type ,
698+ final URI resource , final URI creator , final URI recipient , final URI purpose , final String mode ) {
695699 final Map <String , Object > credential = new HashMap <>();
696700 credential .put (CONTEXT , Arrays .asList (VC_CONTEXT_URI , INRUPT_CONTEXT_URI ));
697701 credential .put ("issuer" , issuer );
698702 credential .put (TYPE , Arrays .asList (type ));
699703
700704 final Map <String , Object > consent = new HashMap <>();
701- if (agent != null ) {
705+ if (recipient != null ) {
702706 if (isAccessGrant (type ) || isAccessDenial (type )) {
703- consent .put (IS_PROVIDED_TO , agent );
707+ consent .put (IS_PROVIDED_TO , recipient );
704708 } else if (isAccessRequest (type )) {
705- consent .put (IS_CONSENT_FOR_DATA_SUBJECT , agent );
709+ consent .put (IS_CONSENT_FOR_DATA_SUBJECT , recipient );
706710 }
707711 }
708712 if (resource != null ) {
@@ -716,13 +720,18 @@ static void buildQuery(final List<Map<String, Object>> queries, final URI issuer
716720 }
717721
718722 final Map <String , Object > subject = new HashMap <>();
723+ if (creator != null ) {
724+ subject .put ("id" , creator );
725+ }
719726 if (!consent .isEmpty ()) {
720727 if (isAccessGrant (type ) || isAccessDenial (type )) {
721728 subject .put (PROVIDED_CONSENT , consent );
722729 } else if (isAccessRequest (type )) {
723730 subject .put ("hasConsent" , consent );
724731 }
725732 credential .put (CREDENTIAL_SUBJECT , subject );
733+ } else if (!subject .isEmpty ()) {
734+ credential .put (CREDENTIAL_SUBJECT , subject );
726735 }
727736
728737 final Map <String , Object > data = new HashMap <>();
@@ -733,7 +742,7 @@ static void buildQuery(final List<Map<String, Object>> queries, final URI issuer
733742 // Recurse
734743 final URI parent = getParent (resource );
735744 if (parent != null ) {
736- buildQuery (queries , issuer , type , agent , parent , purpose , mode );
745+ buildQuery (queries , issuer , type , parent , creator , recipient , purpose , mode );
737746 }
738747 }
739748
@@ -849,35 +858,35 @@ static boolean isSuccess(final int statusCode) {
849858
850859 static Set <String > getAccessRequestTypes () {
851860 final Set <String > types = new HashSet <>();
852- types .add ("SolidAccessRequest" );
853- types .add (ACCESS_REQUEST .toString ());
861+ types .add (SOLID_ACCESS_REQUEST );
862+ types .add (FQ_ACCESS_REQUEST .toString ());
854863 return Collections .unmodifiableSet (types );
855864 }
856865
857866 static Set <String > getAccessGrantTypes () {
858867 final Set <String > types = new HashSet <>();
859- types .add ("SolidAccessGrant" );
860- types .add (ACCESS_GRANT .toString ());
868+ types .add (SOLID_ACCESS_GRANT );
869+ types .add (FQ_ACCESS_GRANT .toString ());
861870 return Collections .unmodifiableSet (types );
862871 }
863872
864873 static Set <String > getAccessDenialTypes () {
865874 final Set <String > types = new HashSet <>();
866- types .add ("SolidAccessDenial" );
867- types .add (ACCESS_DENIAL .toString ());
875+ types .add (SOLID_ACCESS_DENIAL );
876+ types .add (FQ_ACCESS_DENIAL .toString ());
868877 return Collections .unmodifiableSet (types );
869878 }
870879
871880 static boolean isAccessGrant (final URI type ) {
872- return "SolidAccessGrant" .equals (type .toString ()) || ACCESS_GRANT .equals (type );
881+ return SOLID_ACCESS_GRANT .equals (type .toString ()) || FQ_ACCESS_GRANT .equals (type );
873882 }
874883
875884 static boolean isAccessRequest (final URI type ) {
876- return "SolidAccessRequest" .equals (type .toString ()) || ACCESS_REQUEST .equals (type );
885+ return SOLID_ACCESS_REQUEST .equals (type .toString ()) || FQ_ACCESS_REQUEST .equals (type );
877886 }
878887
879888 static boolean isAccessDenial (final URI type ) {
880- return "SolidAccessDenial" .equals (type .toString ()) || ACCESS_DENIAL .equals (type );
889+ return SOLID_ACCESS_DENIAL .equals (type .toString ()) || FQ_ACCESS_DENIAL .equals (type );
881890 }
882891
883892 /**
0 commit comments