@@ -32,6 +32,7 @@ import eu.europa.ec.corelogic.model.FormatType
3232import eu.europa.ec.corelogic.model.ScopedDocumentDomain
3333import eu.europa.ec.corelogic.model.TransactionLogDataDomain
3434import eu.europa.ec.corelogic.model.toDocumentIdentifier
35+ import eu.europa.ec.eudi.openid4vci.CredentialIssuerMetadata
3536import eu.europa.ec.eudi.openid4vci.MsoMdocCredential
3637import eu.europa.ec.eudi.openid4vci.SdJwtVcCredential
3738import eu.europa.ec.eudi.statium.Status
@@ -163,6 +164,7 @@ interface WalletCoreDocumentsController {
163164 fun issueDocument (
164165 issuanceMethod : IssuanceMethod ,
165166 configId : String ,
167+ issuerId : String
166168 ): Flow <IssueDocumentPartialState >
167169
168170 fun issueDocumentsByOfferUri (
@@ -221,8 +223,10 @@ class WalletCoreDocumentsControllerImpl(
221223 private val documentErrorMessage
222224 get() = resourceProvider.getString(R .string.issuance_generic_error)
223225
224- private val openId4VciManager by lazy {
225- eudiWallet.createOpenId4VciManager()
226+ private val openId4VciManagers by lazy {
227+ walletCoreConfig.vciConfig.associate { config ->
228+ config.issuerUrl to eudiWallet.createOpenId4VciManager(config = config)
229+ }
226230 }
227231
228232 override fun getAllDocuments (): List <Document > =
@@ -234,35 +238,43 @@ class WalletCoreDocumentsControllerImpl(
234238 override suspend fun getScopedDocuments (locale : Locale ): FetchScopedDocumentsPartialState {
235239 return withContext(dispatcher) {
236240 runCatching {
237- val metadata = openId4VciManager.getIssuerMetadata().getOrThrow()
238241
239- val documents =
240- metadata.credentialConfigurationsSupported.map { (id, config) ->
242+ val metadata: Map <String , CredentialIssuerMetadata > =
243+ openId4VciManagers.mapValues { (_, manager) ->
244+ manager.getIssuerMetadata().getOrThrow()
245+ }
241246
242- val name: String = config.display.getLocalizedDisplayName(
243- userLocale = locale,
244- fallback = id.value
245- )
247+ val documents: List <ScopedDocumentDomain > =
248+ metadata.flatMap { (issuer, meta) ->
249+ meta.credentialConfigurationsSupported.map { (id, config) ->
246250
247- val isPid: Boolean = when (config) {
248- is MsoMdocCredential -> config.docType.toDocumentIdentifier() == DocumentIdentifier .MdocPid
249- is SdJwtVcCredential -> config.type.toDocumentIdentifier() == DocumentIdentifier .SdJwtPid
250- else -> false
251- }
251+ val name = config.display.getLocalizedDisplayName(
252+ userLocale = locale,
253+ fallback = id.value
254+ )
252255
253- val formatType = when (config) {
254- is MsoMdocCredential -> config.docType
255- is SdJwtVcCredential -> config.type
256- else -> null
257- }
256+ val isPid = when (config) {
257+ is MsoMdocCredential -> config.docType.toDocumentIdentifier() == DocumentIdentifier . MdocPid
258+ is SdJwtVcCredential -> config.type.toDocumentIdentifier() == DocumentIdentifier . SdJwtPid
259+ else -> false
260+ }
258261
259- ScopedDocumentDomain (
260- name = name,
261- configurationId = id.value,
262- formatType = formatType,
263- isPid = isPid
264- )
262+ val formatType = when (config) {
263+ is MsoMdocCredential -> config.docType
264+ is SdJwtVcCredential -> config.type
265+ else -> null
266+ }
267+
268+ ScopedDocumentDomain (
269+ name = name,
270+ configurationId = id.value,
271+ credentialIssuerId = issuer,
272+ formatType = formatType,
273+ isPid = isPid
274+ )
275+ }
265276 }
277+
266278 if (documents.isNotEmpty()) {
267279 FetchScopedDocumentsPartialState .Success (documents = documents)
268280 } else {
@@ -306,11 +318,11 @@ class WalletCoreDocumentsControllerImpl(
306318 override fun issueDocument (
307319 issuanceMethod : IssuanceMethod ,
308320 configId : String ,
321+ issuerId : String
309322 ): Flow <IssueDocumentPartialState > = flow {
310323 when (issuanceMethod) {
311-
312324 IssuanceMethod .OPENID4VCI -> {
313- issueDocumentWithOpenId4VCI(configId).collect { response ->
325+ issueDocumentWithOpenId4VCI(configId, issuerId ).collect { response ->
314326 when (response) {
315327 is IssueDocumentsPartialState .Failure -> emit(
316328 IssueDocumentPartialState .Failure (
@@ -355,11 +367,30 @@ class WalletCoreDocumentsControllerImpl(
355367 txCode : String? ,
356368 ): Flow <IssueDocumentsPartialState > =
357369 callbackFlow {
358- openId4VciManager.issueDocumentByOfferUri(
359- offerUri = offerUri,
360- onIssueEvent = issuanceCallback(),
361- txCode = txCode,
362- )
370+ resolveDocumentOffer(offerUri).collect {
371+ when (it) {
372+ is ResolveDocumentOfferPartialState .Failure -> throw Throwable (it.errorMessage)
373+ is ResolveDocumentOfferPartialState .Success -> {
374+
375+ val issuerId = it
376+ .offer
377+ .credentialOffer
378+ .credentialIssuerIdentifier
379+ .toString()
380+
381+ val manager = openId4VciManagers[issuerId]
382+ ? : openId4VciManagers.values.firstOrNull()
383+
384+ require(manager != null ) { documentErrorMessage }
385+
386+ manager.issueDocumentByOffer(
387+ offer = it.offer,
388+ onIssueEvent = issuanceCallback(),
389+ txCode = txCode,
390+ )
391+ }
392+ }
393+ }
363394 awaitClose()
364395 }.safeAsync {
365396 IssueDocumentsPartialState .Failure (
@@ -452,30 +483,25 @@ class WalletCoreDocumentsControllerImpl(
452483
453484 override fun resolveDocumentOffer (offerUri : String ): Flow <ResolveDocumentOfferPartialState > =
454485 callbackFlow {
455- openId4VciManager.resolveDocumentOffer(
456- offerUri = offerUri,
457- onResolvedOffer = { offerResult ->
458- when (offerResult) {
459- is OfferResult .Failure -> {
460- trySendBlocking(
461- ResolveDocumentOfferPartialState .Failure (
462- errorMessage = offerResult.cause.localizedMessage
463- ? : genericErrorMessage
464- )
465- )
466- }
467486
468- is OfferResult .Success -> {
469- trySendBlocking(
470- ResolveDocumentOfferPartialState .Success (
471- offer = offerResult.offer
472- )
487+ val manager = openId4VciManagers.values.firstOrNull()
488+ require(manager != null ) { genericErrorMessage }
489+
490+ manager.resolveDocumentOffer(offerUri) { result ->
491+ when (result) {
492+ is OfferResult .Failure -> throw Throwable (
493+ result.cause.localizedMessage ? : genericErrorMessage
494+ )
495+
496+ is OfferResult .Success -> {
497+ trySendBlocking(
498+ ResolveDocumentOfferPartialState .Success (
499+ offer = result.offer
473500 )
474- }
501+ )
475502 }
476503 }
477- )
478-
504+ }
479505 awaitClose()
480506 }.safeAsync {
481507 ResolveDocumentOfferPartialState .Failure (
@@ -486,7 +512,14 @@ class WalletCoreDocumentsControllerImpl(
486512 override fun issueDeferredDocument (docId : DocumentId ): Flow <IssueDeferredDocumentPartialState > =
487513 callbackFlow {
488514 (getDocumentById(docId) as ? DeferredDocument )?.let { deferredDoc ->
489- openId4VciManager.issueDeferredDocument(
515+
516+ val manager = deferredDoc.issuerMetadata?.credentialIssuerIdentifier
517+ ?.let (openId4VciManagers::get)
518+ ? : openId4VciManagers.values.firstOrNull()
519+
520+ require(manager != null ) { documentErrorMessage }
521+
522+ manager.issueDeferredDocument(
490523 deferredDocument = deferredDoc,
491524 executor = null ,
492525 onIssueResult = { deferredIssuanceResult ->
@@ -551,7 +584,13 @@ class WalletCoreDocumentsControllerImpl(
551584 }
552585
553586 override fun resumeOpenId4VciWithAuthorization (uri : String ) {
554- openId4VciManager.resumeWithAuthorization(uri)
587+ for (manager in openId4VciManagers.values) {
588+ try {
589+ manager.resumeWithAuthorization(uri)
590+ break
591+ } catch (_: Exception ) {
592+ }
593+ }
555594 }
556595
557596 override fun getAllDocumentCategories (): DocumentCategories {
@@ -602,10 +641,16 @@ class WalletCoreDocumentsControllerImpl(
602641 override suspend fun resolveDocumentStatus (document : IssuedDocument ): Result <Status > =
603642 eudiWallet.resolveStatus(document)
604643
605- private fun issueDocumentWithOpenId4VCI (configId : String ): Flow <IssueDocumentsPartialState > =
644+ private fun issueDocumentWithOpenId4VCI (
645+ configId : String ,
646+ issuerId : String
647+ ): Flow <IssueDocumentsPartialState > =
606648 callbackFlow {
607649
608- openId4VciManager.issueDocumentByConfigurationIdentifier(
650+ val manager = openId4VciManagers[issuerId]
651+ require(manager != null ) { documentErrorMessage }
652+
653+ manager.issueDocumentByConfigurationIdentifier(
609654 credentialConfigurationId = configId,
610655 onIssueEvent = issuanceCallback()
611656 )
0 commit comments