@@ -107,6 +107,7 @@ public class AccessGrantClient {
107107 private static final String PROVIDED_CONSENT = "providedConsent" ;
108108 private static final String FOR_PURPOSE = "forPurpose" ;
109109 private static final String EXPIRATION_DATE = "expirationDate" ;
110+ private static final String ISSUANCE_DATE = "issuanceDate" ;
110111 private static final String CREDENTIAL = "credential" ;
111112 private static final String SOLID_ACCESS_GRANT = "SolidAccessGrant" ;
112113 private static final String SOLID_ACCESS_REQUEST = "SolidAccessRequest" ;
@@ -180,6 +181,17 @@ public AccessGrantClient session(final Session session) {
180181 return new AccessGrantClient (client .session (session ), metadataCache , config );
181182 }
182183
184+ /**
185+ * Issue an access request.
186+ *
187+ * @param request the parameters for the access request
188+ * @return the next stage of completion containing the resulting access request
189+ */
190+ public CompletionStage <AccessRequest > requestAccess (final AccessRequest .RequestParameters request ) {
191+ return requestAccess (request .getRecipient (), request .getResources (),
192+ request .getModes (), request .getPurposes (), request .getExpiration (), request .getIssuedAt ());
193+ }
194+
183195 /**
184196 * Issue an access request.
185197 *
@@ -192,10 +204,16 @@ public AccessGrantClient session(final Session session) {
192204 */
193205 public CompletionStage <AccessRequest > requestAccess (final URI recipient , final Set <URI > resources ,
194206 final Set <String > modes , final Set <URI > purposes , final Instant expiration ) {
207+ return requestAccess (recipient , resources , modes , purposes , expiration , null );
208+ }
209+
210+ private CompletionStage <AccessRequest > requestAccess (final URI recipient , final Set <URI > resources ,
211+ final Set <String > modes , final Set <URI > purposes , final Instant expiration , final Instant issuance ) {
195212 Objects .requireNonNull (resources , "Resources may not be null!" );
196213 Objects .requireNonNull (modes , "Access modes may not be null!" );
197214 return v1Metadata ().thenCompose (metadata -> {
198- final Map <String , Object > data = buildAccessRequestv1 (recipient , resources , modes , expiration , purposes );
215+ final Map <String , Object > data = buildAccessRequestv1 (recipient , resources , modes , purposes , expiration ,
216+ issuance );
199217
200218 final Request req = Request .newBuilder (metadata .issueEndpoint )
201219 .header (CONTENT_TYPE , APPLICATION_JSON )
@@ -228,7 +246,7 @@ public CompletionStage<AccessGrant> grantAccess(final AccessRequest request) {
228246 Objects .requireNonNull (request , "Request may not be null!" );
229247 return v1Metadata ().thenCompose (metadata -> {
230248 final Map <String , Object > data = buildAccessGrantv1 (request .getCreator (), request .getResources (),
231- request .getModes (), request .getExpiration (), request .getPurposes ());
249+ request .getModes (), request .getPurposes (), request . getExpiration (), request .getIssuedAt ());
232250 final Request req = Request .newBuilder (metadata .issueEndpoint )
233251 .header (CONTENT_TYPE , APPLICATION_JSON )
234252 .POST (Request .BodyPublishers .ofByteArray (serialize (data ))).build ();
@@ -260,7 +278,7 @@ public CompletionStage<AccessDenial> denyAccess(final AccessRequest request) {
260278 Objects .requireNonNull (request , "Request may not be null!" );
261279 return v1Metadata ().thenCompose (metadata -> {
262280 final Map <String , Object > data = buildAccessDenialv1 (request .getCreator (), request .getResources (),
263- request .getModes (), request .getExpiration (), request .getPurposes ());
281+ request .getModes (), request .getPurposes (), request . getExpiration (), request .getIssuedAt ());
264282 final Request req = Request .newBuilder (metadata .issueEndpoint )
265283 .header (CONTENT_TYPE , APPLICATION_JSON )
266284 .POST (Request .BodyPublishers .ofByteArray (serialize (data ))).build ();
@@ -311,9 +329,9 @@ public CompletionStage<AccessGrant> issue(final URI type, final URI recipient, f
311329 return v1Metadata ().thenCompose (metadata -> {
312330 final Map <String , Object > data ;
313331 if (FQ_ACCESS_GRANT .equals (type )) {
314- data = buildAccessGrantv1 (recipient , resources , modes , expiration , uriPurposes );
332+ data = buildAccessGrantv1 (recipient , resources , modes , uriPurposes , expiration , null );
315333 } else if (FQ_ACCESS_REQUEST .equals (type )) {
316- data = buildAccessRequestv1 (recipient , resources , modes , expiration , uriPurposes );
334+ data = buildAccessRequestv1 (recipient , resources , modes , uriPurposes , expiration , null );
317335 } else {
318336 throw new AccessGrantException ("Unsupported grant type: " + type );
319337 }
@@ -809,7 +827,7 @@ static URI asUri(final Object value) {
809827 }
810828
811829 static Map <String , Object > buildAccessDenialv1 (final URI agent , final Set <URI > resources , final Set <String > modes ,
812- final Instant expiration , final Set < URI > purposes ) {
830+ final Set < URI > purposes , final Instant expiration , final Instant issuance ) {
813831 Objects .requireNonNull (agent , "Access denial agent may not be null!" );
814832 final Map <String , Object > consent = new HashMap <>();
815833 consent .put (MODE , modes );
@@ -828,6 +846,9 @@ static Map<String, Object> buildAccessDenialv1(final URI agent, final Set<URI> r
828846 if (expiration != null ) {
829847 credential .put (EXPIRATION_DATE , expiration .truncatedTo (ChronoUnit .SECONDS ).toString ());
830848 }
849+ if (issuance != null ) {
850+ credential .put (ISSUANCE_DATE , issuance .truncatedTo (ChronoUnit .SECONDS ).toString ());
851+ }
831852 credential .put (CREDENTIAL_SUBJECT , subject );
832853
833854 final Map <String , Object > data = new HashMap <>();
@@ -836,7 +857,7 @@ static Map<String, Object> buildAccessDenialv1(final URI agent, final Set<URI> r
836857 }
837858
838859 static Map <String , Object > buildAccessGrantv1 (final URI agent , final Set <URI > resources , final Set <String > modes ,
839- final Instant expiration , final Set < URI > purposes ) {
860+ final Set < URI > purposes , final Instant expiration , final Instant issuance ) {
840861 Objects .requireNonNull (agent , "Access grant agent may not be null!" );
841862 final Map <String , Object > consent = new HashMap <>();
842863 consent .put (MODE , modes );
@@ -855,6 +876,9 @@ static Map<String, Object> buildAccessGrantv1(final URI agent, final Set<URI> re
855876 if (expiration != null ) {
856877 credential .put (EXPIRATION_DATE , expiration .truncatedTo (ChronoUnit .SECONDS ).toString ());
857878 }
879+ if (issuance != null ) {
880+ credential .put (ISSUANCE_DATE , issuance .truncatedTo (ChronoUnit .SECONDS ).toString ());
881+ }
858882 credential .put (CREDENTIAL_SUBJECT , subject );
859883
860884 final Map <String , Object > data = new HashMap <>();
@@ -863,7 +887,7 @@ static Map<String, Object> buildAccessGrantv1(final URI agent, final Set<URI> re
863887 }
864888
865889 static Map <String , Object > buildAccessRequestv1 (final URI agent , final Set <URI > resources , final Set <String > modes ,
866- final Instant expiration , final Set < URI > purposes ) {
890+ final Set < URI > purposes , final Instant expiration , final Instant issuance ) {
867891 final Map <String , Object > consent = new HashMap <>();
868892 consent .put (HAS_STATUS , "https://w3id.org/GConsent#ConsentStatusRequested" );
869893 consent .put (MODE , modes );
@@ -883,6 +907,10 @@ static Map<String, Object> buildAccessRequestv1(final URI agent, final Set<URI>
883907 if (expiration != null ) {
884908 credential .put (EXPIRATION_DATE , expiration .truncatedTo (ChronoUnit .SECONDS ).toString ());
885909 }
910+ if (issuance != null ) {
911+ credential .put (ISSUANCE_DATE , issuance .truncatedTo (ChronoUnit .SECONDS ).toString ());
912+ }
913+
886914 credential .put (CREDENTIAL_SUBJECT , subject );
887915
888916 final Map <String , Object > data = new HashMap <>();
0 commit comments