mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
CORDA-1335: Scan attachment Jar only to speed-up the process. (#2982)
* CORDA-1335: Scan attachment Jar only to speed-up the process. * CORDA-1335: Explicitly mention other types of contracts to scan. * CORDA-1335: Refactor to eliminate listing different subclasses of Contract in two separate places.
This commit is contained in:
parent
247a97f1a5
commit
bf4d8ba08c
@ -3,40 +3,53 @@ package net.corda.nodeapi.internal
|
||||
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner
|
||||
import net.corda.core.contracts.Contract
|
||||
import net.corda.core.contracts.ContractClassName
|
||||
import net.corda.core.contracts.UpgradedContract
|
||||
import net.corda.core.contracts.UpgradedContractWithLegacyConstraint
|
||||
import net.corda.core.internal.copyTo
|
||||
import net.corda.core.internal.deleteIfExists
|
||||
import net.corda.core.internal.logElapsedTime
|
||||
import net.corda.core.internal.read
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.io.InputStream
|
||||
import java.lang.reflect.Modifier
|
||||
import java.net.URLClassLoader
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import java.nio.file.StandardCopyOption
|
||||
import java.util.Collections.singleton
|
||||
|
||||
// When scanning of the CorDapp Jar is performed without "corda-core.jar" being the in the classpath, there is no way to appreciate
|
||||
// relationships between those interfaces, therefore they have to be listed explicitly.
|
||||
val coreContractClasses = setOf(Contract::class, UpgradedContractWithLegacyConstraint::class, UpgradedContract::class)
|
||||
|
||||
/**
|
||||
* Scans the jar for contracts.
|
||||
* @returns: found contract class names or null if none found
|
||||
*/
|
||||
fun scanJarForContracts(cordappJar: Path): List<ContractClassName> {
|
||||
val currentClassLoader = Contract::class.java.classLoader
|
||||
val scanResult = FastClasspathScanner()
|
||||
.addClassLoader(currentClassLoader)
|
||||
.overrideClasspath(cordappJar, Paths.get(Contract::class.java.protectionDomain.codeSource.location.toURI()))
|
||||
// A set of a single element may look odd, but if this is removed "Path" which itself is an `Iterable`
|
||||
// is getting broken into pieces to scan individually, which doesn't yield desired effect.
|
||||
.overrideClasspath(singleton(cordappJar))
|
||||
.scan()
|
||||
val contracts = (scanResult.getNamesOfClassesImplementing(Contract::class.qualifiedName) ).distinct()
|
||||
val contracts = coreContractClasses.flatMap { contractClass -> scanResult.getNamesOfClassesImplementing(contractClass.qualifiedName) }.distinct()
|
||||
|
||||
// Only keep instantiable contracts
|
||||
return URLClassLoader(arrayOf(cordappJar.toUri().toURL()), currentClassLoader).use {
|
||||
return URLClassLoader(arrayOf(cordappJar.toUri().toURL()), Contract::class.java.classLoader).use {
|
||||
contracts.map(it::loadClass).filter { !it.isInterface && !Modifier.isAbstract(it.modifiers) }
|
||||
}.map { it.name }
|
||||
}
|
||||
|
||||
private val logger = LoggerFactory.getLogger("ClassloaderUtils")
|
||||
|
||||
fun <T> withContractsInJar(jarInputStream: InputStream, withContracts: (List<ContractClassName>, InputStream) -> T): T {
|
||||
val tempFile = Files.createTempFile("attachment", ".jar")
|
||||
try {
|
||||
jarInputStream.copyTo(tempFile, StandardCopyOption.REPLACE_EXISTING)
|
||||
val contracts = scanJarForContracts(tempFile.toAbsolutePath())
|
||||
val cordappJar = tempFile.toAbsolutePath()
|
||||
val contracts = logElapsedTime("Contracts loading for '$cordappJar'", logger) {
|
||||
scanJarForContracts(cordappJar)
|
||||
}
|
||||
return tempFile.read { withContracts(contracts, it) }
|
||||
} finally {
|
||||
tempFile.deleteIfExists()
|
||||
|
@ -17,6 +17,7 @@ import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.node.internal.classloading.requireAnnotation
|
||||
import net.corda.node.services.config.NodeConfiguration
|
||||
import net.corda.nodeapi.internal.coreContractClasses
|
||||
import net.corda.nodeapi.internal.serialization.DefaultWhitelist
|
||||
import org.apache.commons.collections4.map.LRUMap
|
||||
import java.io.File
|
||||
@ -241,13 +242,7 @@ class CordappLoader private constructor(private val cordappJarPaths: List<Restri
|
||||
}
|
||||
|
||||
private fun findContractClassNames(scanResult: RestrictedScanResult): List<String> {
|
||||
return (scanResult.getNamesOfClassesImplementing(Contract::class) +
|
||||
scanResult.getNamesOfClassesImplementing(UpgradedContract::class) +
|
||||
// Even though UpgradedContractWithLegacyConstraint implements UpgradedContract
|
||||
// we need to specify it separately. Otherwise, classes implementing UpgradedContractWithLegacyConstraint
|
||||
// don't get picked up.
|
||||
scanResult.getNamesOfClassesImplementing(UpgradedContractWithLegacyConstraint::class))
|
||||
.distinct()
|
||||
return coreContractClasses.flatMap { scanResult.getNamesOfClassesImplementing(it) }.distinct()
|
||||
}
|
||||
|
||||
private fun findPlugins(cordappJarPath: RestrictedURL): List<SerializationWhitelist> {
|
||||
|
Loading…
Reference in New Issue
Block a user