diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 9837cf9f86..e300f92449 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -7,6 +7,10 @@ release, see :doc:`upgrade-notes`. Unreleased ========== +* Fixed incorrect exception handling in ``NodeVaultService._query()``. + +* Avoided a memory leak deriving from incorrect MappedSchema caching strategy. + * Fix CORDA-1403 where a property of a class that implemented a generic interface could not be deserialised in a factory without a serialiser as the subtype check for the class instance failed. Fix is to compare the raw type. diff --git a/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt b/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt index 3134c57d1b..dc09057558 100644 --- a/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt +++ b/node/src/main/kotlin/net/corda/node/services/vault/NodeVaultService.kt @@ -396,65 +396,60 @@ class NodeVaultService( // TODO: revisit (use single instance of parser for all queries) val criteriaParser = HibernateQueryCriteriaParser(contractStateType, contractStateTypeMappings, criteriaBuilder, criteriaQuery, queryRootVaultStates) - try { - // parse criteria and build where predicates - criteriaParser.parse(criteria, sorting) + // parse criteria and build where predicates + criteriaParser.parse(criteria, sorting) - // prepare query for execution - val query = session.createQuery(criteriaQuery) + // prepare query for execution + val query = session.createQuery(criteriaQuery) - // pagination checks - if (!paging.isDefault) { - // pagination - if (paging.pageNumber < DEFAULT_PAGE_NUM) throw VaultQueryException("Page specification: invalid page number ${paging.pageNumber} [page numbers start from $DEFAULT_PAGE_NUM]") - if (paging.pageSize < 1) throw VaultQueryException("Page specification: invalid page size ${paging.pageSize} [must be a value between 1 and $MAX_PAGE_SIZE]") - } - - query.firstResult = (paging.pageNumber - 1) * paging.pageSize - query.maxResults = paging.pageSize + 1 // detection too many results - - // execution - val results = query.resultList - - // final pagination check (fail-fast on too many results when no pagination specified) - if (paging.isDefault && results.size > DEFAULT_PAGE_SIZE) - throw VaultQueryException("Please specify a `PageSpecification` as there are more results [${results.size}] than the default page size [$DEFAULT_PAGE_SIZE]") - - val statesAndRefs: MutableList> = mutableListOf() - val statesMeta: MutableList = mutableListOf() - val otherResults: MutableList = mutableListOf() - val stateRefs = mutableSetOf() - - results.asSequence() - .forEachIndexed { index, result -> - if (result[0] is VaultSchemaV1.VaultStates) { - if (!paging.isDefault && index == paging.pageSize) // skip last result if paged - return@forEachIndexed - val vaultState = result[0] as VaultSchemaV1.VaultStates - val stateRef = StateRef(SecureHash.parse(vaultState.stateRef!!.txId!!), vaultState.stateRef!!.index!!) - stateRefs.add(stateRef) - statesMeta.add(Vault.StateMetadata(stateRef, - vaultState.contractStateClassName, - vaultState.recordedTime, - vaultState.consumedTime, - vaultState.stateStatus, - vaultState.notary, - vaultState.lockId, - vaultState.lockUpdateTime)) - } else { - // TODO: improve typing of returned other results - log.debug { "OtherResults: ${Arrays.toString(result.toArray())}" } - otherResults.addAll(result.toArray().asList()) - } - } - if (stateRefs.isNotEmpty()) - statesAndRefs.addAll(servicesForResolution.loadStates(stateRefs) as Collection>) - - return Vault.Page(states = statesAndRefs, statesMetadata = statesMeta, stateTypes = criteriaParser.stateTypes, totalStatesAvailable = totalStates, otherResults = otherResults) - } catch (e: java.lang.Exception) { - log.error(e.message) - throw e.cause ?: e + // pagination checks + if (!paging.isDefault) { + // pagination + if (paging.pageNumber < DEFAULT_PAGE_NUM) throw VaultQueryException("Page specification: invalid page number ${paging.pageNumber} [page numbers start from $DEFAULT_PAGE_NUM]") + if (paging.pageSize < 1) throw VaultQueryException("Page specification: invalid page size ${paging.pageSize} [must be a value between 1 and $MAX_PAGE_SIZE]") } + + query.firstResult = (paging.pageNumber - 1) * paging.pageSize + query.maxResults = paging.pageSize + 1 // detection too many results + + // execution + val results = query.resultList + + // final pagination check (fail-fast on too many results when no pagination specified) + if (paging.isDefault && results.size > DEFAULT_PAGE_SIZE) + throw VaultQueryException("Please specify a `PageSpecification` as there are more results [${results.size}] than the default page size [$DEFAULT_PAGE_SIZE]") + + val statesAndRefs: MutableList> = mutableListOf() + val statesMeta: MutableList = mutableListOf() + val otherResults: MutableList = mutableListOf() + val stateRefs = mutableSetOf() + + results.asSequence() + .forEachIndexed { index, result -> + if (result[0] is VaultSchemaV1.VaultStates) { + if (!paging.isDefault && index == paging.pageSize) // skip last result if paged + return@forEachIndexed + val vaultState = result[0] as VaultSchemaV1.VaultStates + val stateRef = StateRef(SecureHash.parse(vaultState.stateRef!!.txId!!), vaultState.stateRef!!.index!!) + stateRefs.add(stateRef) + statesMeta.add(Vault.StateMetadata(stateRef, + vaultState.contractStateClassName, + vaultState.recordedTime, + vaultState.consumedTime, + vaultState.stateStatus, + vaultState.notary, + vaultState.lockId, + vaultState.lockUpdateTime)) + } else { + // TODO: improve typing of returned other results + log.debug { "OtherResults: ${Arrays.toString(result.toArray())}" } + otherResults.addAll(result.toArray().asList()) + } + } + if (stateRefs.isNotEmpty()) + statesAndRefs.addAll(servicesForResolution.loadStates(stateRefs) as Collection>) + + return Vault.Page(states = statesAndRefs, statesMetadata = statesMeta, stateTypes = criteriaParser.stateTypes, totalStatesAvailable = totalStates, otherResults = otherResults) } @Throws(VaultQueryException::class)