mirror of
https://github.com/corda/corda.git
synced 2025-06-16 22:28:15 +00:00
Safe parsing of min platform version and target version from CorDapp MANIFEST files (#4031)
Also includes some cleanup
This commit is contained in:
@ -42,8 +42,7 @@ data class CordappImpl(
|
|||||||
// TODO Why a seperate Info class and not just have the fields directly in CordappImpl?
|
// TODO Why a seperate Info class and not just have the fields directly in CordappImpl?
|
||||||
data class Info(val shortName: String, val vendor: String, val version: String, val minimumPlatformVersion: Int, val targetPlatformVersion: Int) {
|
data class Info(val shortName: String, val vendor: String, val version: String, val minimumPlatformVersion: Int, val targetPlatformVersion: Int) {
|
||||||
companion object {
|
companion object {
|
||||||
private const val UNKNOWN_VALUE = "Unknown"
|
const val UNKNOWN_VALUE = "Unknown"
|
||||||
|
|
||||||
val UNKNOWN = Info(UNKNOWN_VALUE, UNKNOWN_VALUE, UNKNOWN_VALUE, 1, 1)
|
val UNKNOWN = Info(UNKNOWN_VALUE, UNKNOWN_VALUE, UNKNOWN_VALUE, 1, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,10 +112,12 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
|
|||||||
)
|
)
|
||||||
|
|
||||||
private fun loadCordapps(): List<CordappImpl> {
|
private fun loadCordapps(): List<CordappImpl> {
|
||||||
val cordapps = cordappJarPaths.map { scanCordapp(it).toCordapp(it) }
|
val cordapps = cordappJarPaths
|
||||||
|
.map { scanCordapp(it).toCordapp(it) }
|
||||||
.filter {
|
.filter {
|
||||||
if (it.info.minimumPlatformVersion > versionInfo.platformVersion) {
|
if (it.info.minimumPlatformVersion > versionInfo.platformVersion) {
|
||||||
logger.warn("Not loading CorDapp ${it.info.shortName} (${it.info.vendor}) as it requires minimum platform version ${it.info.minimumPlatformVersion} (This node is running version ${versionInfo.platformVersion}).")
|
logger.warn("Not loading CorDapp ${it.info.shortName} (${it.info.vendor}) as it requires minimum " +
|
||||||
|
"platform version ${it.info.minimumPlatformVersion} (This node is running version ${versionInfo.platformVersion}).")
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
@ -126,7 +128,7 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun RestrictedScanResult.toCordapp(url: RestrictedURL): CordappImpl {
|
private fun RestrictedScanResult.toCordapp(url: RestrictedURL): CordappImpl {
|
||||||
val info = url.url.openStream().let(::JarInputStream).use { it.manifest }.toCordappInfo(CordappImpl.jarName(url.url))
|
val info = url.url.openStream().let(::JarInputStream).use { it.manifest?.toCordappInfo(CordappImpl.jarName(url.url)) ?: CordappImpl.Info.UNKNOWN }
|
||||||
return CordappImpl(
|
return CordappImpl(
|
||||||
findContractClassNames(this),
|
findContractClassNames(this),
|
||||||
findInitiatedFlows(this),
|
findInitiatedFlows(this),
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.corda.node.internal.cordapp
|
package net.corda.node.internal.cordapp
|
||||||
|
|
||||||
import net.corda.core.internal.cordapp.CordappImpl
|
import net.corda.core.internal.cordapp.CordappImpl
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Info.Companion.UNKNOWN_VALUE
|
||||||
import java.util.jar.Attributes
|
import java.util.jar.Attributes
|
||||||
import java.util.jar.Manifest
|
import java.util.jar.Manifest
|
||||||
|
|
||||||
@ -23,23 +24,23 @@ fun createTestManifest(name: String, title: String, version: String, vendor: Str
|
|||||||
return manifest
|
return manifest
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun Manifest.set(key: String, value: String) {
|
operator fun Manifest.set(key: String, value: String): String? {
|
||||||
mainAttributes.putValue(key, value)
|
return mainAttributes.putValue(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Manifest?.toCordappInfo(defaultShortName: String): CordappImpl.Info {
|
operator fun Manifest.get(key: String): String? = mainAttributes.getValue(key)
|
||||||
var info = CordappImpl.Info.UNKNOWN
|
|
||||||
(this?.mainAttributes?.getValue("Name") ?: defaultShortName).let { shortName ->
|
fun Manifest.toCordappInfo(defaultShortName: String): CordappImpl.Info {
|
||||||
info = info.copy(shortName = shortName)
|
val shortName = this["Name"] ?: defaultShortName
|
||||||
}
|
val vendor = this["Implementation-Vendor"] ?: UNKNOWN_VALUE
|
||||||
this?.mainAttributes?.getValue("Implementation-Vendor")?.let { vendor ->
|
val version = this["Implementation-Version"] ?: UNKNOWN_VALUE
|
||||||
info = info.copy(vendor = vendor)
|
val minPlatformVersion = this["Min-Platform-Version"]?.toIntOrNull() ?: 1
|
||||||
}
|
val targetPlatformVersion = this["Target-Platform-Version"]?.toIntOrNull() ?: minPlatformVersion
|
||||||
this?.mainAttributes?.getValue("Implementation-Version")?.let { version ->
|
return CordappImpl.Info(
|
||||||
info = info.copy(version = version)
|
shortName = shortName,
|
||||||
}
|
vendor = vendor,
|
||||||
val minPlatformVersion = this?.mainAttributes?.getValue("Min-Platform-Version")?.toInt() ?: 1
|
version = version,
|
||||||
val targetPlatformVersion = this?.mainAttributes?.getValue("Target-Platform-Version")?.toInt() ?: minPlatformVersion
|
minimumPlatformVersion = minPlatformVersion,
|
||||||
info = info.copy(minimumPlatformVersion = minPlatformVersion, targetPlatformVersion = targetPlatformVersion)
|
targetPlatformVersion = targetPlatformVersion
|
||||||
return info
|
)
|
||||||
}
|
}
|
@ -4,7 +4,6 @@ import co.paralleluniverse.fibers.Suspendable
|
|||||||
import net.corda.core.flows.*
|
import net.corda.core.flows.*
|
||||||
import net.corda.node.VersionInfo
|
import net.corda.node.VersionInfo
|
||||||
import net.corda.node.cordapp.CordappLoader
|
import net.corda.node.cordapp.CordappLoader
|
||||||
import net.corda.nodeapi.internal.PLATFORM_VERSION
|
|
||||||
import net.corda.testing.node.internal.cordappsForPackages
|
import net.corda.testing.node.internal.cordappsForPackages
|
||||||
import net.corda.testing.node.internal.getTimestampAsDirectoryName
|
import net.corda.testing.node.internal.getTimestampAsDirectoryName
|
||||||
import net.corda.testing.node.internal.packageInDirectory
|
import net.corda.testing.node.internal.packageInDirectory
|
||||||
@ -45,7 +44,7 @@ class JarScanningCordappLoaderTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test that classes that aren't in cordapps aren't loaded`() {
|
fun `classes that aren't in cordapps aren't loaded`() {
|
||||||
// Basedir will not be a corda node directory so the dummy flow shouldn't be recognised as a part of a cordapp
|
// Basedir will not be a corda node directory so the dummy flow shouldn't be recognised as a part of a cordapp
|
||||||
val loader = JarScanningCordappLoader.fromDirectories(listOf(Paths.get(".")))
|
val loader = JarScanningCordappLoader.fromDirectories(listOf(Paths.get(".")))
|
||||||
assertThat(loader.cordapps).containsOnly(loader.coreCordapp)
|
assertThat(loader.cordapps).containsOnly(loader.coreCordapp)
|
||||||
@ -56,10 +55,9 @@ class JarScanningCordappLoaderTest {
|
|||||||
val isolatedJAR = JarScanningCordappLoaderTest::class.java.getResource("isolated.jar")!!
|
val isolatedJAR = JarScanningCordappLoaderTest::class.java.getResource("isolated.jar")!!
|
||||||
val loader = JarScanningCordappLoader.fromJarUrls(listOf(isolatedJAR))
|
val loader = JarScanningCordappLoader.fromJarUrls(listOf(isolatedJAR))
|
||||||
|
|
||||||
val actual = loader.cordapps.toTypedArray()
|
assertThat(loader.cordapps).hasSize(2)
|
||||||
assertThat(actual).hasSize(2)
|
|
||||||
|
|
||||||
val actualCordapp = actual.single { it != loader.coreCordapp }
|
val actualCordapp = loader.cordapps.single { it != loader.coreCordapp }
|
||||||
assertThat(actualCordapp.contractClassNames).isEqualTo(listOf(isolatedContractId))
|
assertThat(actualCordapp.contractClassNames).isEqualTo(listOf(isolatedContractId))
|
||||||
assertThat(actualCordapp.initiatedFlows.single().name).isEqualTo("net.corda.finance.contracts.isolated.IsolatedDummyFlow\$Acceptor")
|
assertThat(actualCordapp.initiatedFlows.single().name).isEqualTo("net.corda.finance.contracts.isolated.IsolatedDummyFlow\$Acceptor")
|
||||||
assertThat(actualCordapp.rpcFlows).isEmpty()
|
assertThat(actualCordapp.rpcFlows).isEmpty()
|
||||||
@ -113,7 +111,7 @@ class JarScanningCordappLoaderTest {
|
|||||||
fun `cordapp classloader sets target and min version to 1 if not specified`() {
|
fun `cordapp classloader sets target and min version to 1 if not specified`() {
|
||||||
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/no-min-or-target-version.jar")!!
|
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/no-min-or-target-version.jar")!!
|
||||||
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN)
|
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN)
|
||||||
loader.cordapps.filter { !it.info.shortName.equals("corda-core") }.forEach {
|
loader.cordapps.filter { it.info.shortName != "corda-core" }.forEach {
|
||||||
assertThat(it.info.targetPlatformVersion).isEqualTo(1)
|
assertThat(it.info.targetPlatformVersion).isEqualTo(1)
|
||||||
assertThat(it.info.minimumPlatformVersion).isEqualTo(1)
|
assertThat(it.info.minimumPlatformVersion).isEqualTo(1)
|
||||||
}
|
}
|
||||||
@ -126,7 +124,7 @@ class JarScanningCordappLoaderTest {
|
|||||||
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!!
|
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!!
|
||||||
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN)
|
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN)
|
||||||
// exclude the core cordapp
|
// exclude the core cordapp
|
||||||
val cordapp = loader.cordapps.filter { it.cordappClasses.contains("net.corda.core.internal.cordapp.CordappImpl")}.single()
|
val cordapp = loader.cordapps.single { it.cordappClasses.contains("net.corda.core.internal.cordapp.CordappImpl") }
|
||||||
assertThat(cordapp.info.targetPlatformVersion).isEqualTo(3)
|
assertThat(cordapp.info.targetPlatformVersion).isEqualTo(3)
|
||||||
assertThat(cordapp.info.minimumPlatformVersion).isEqualTo(2)
|
assertThat(cordapp.info.minimumPlatformVersion).isEqualTo(2)
|
||||||
}
|
}
|
||||||
@ -137,17 +135,17 @@ class JarScanningCordappLoaderTest {
|
|||||||
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-no-target.jar")!!
|
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-no-target.jar")!!
|
||||||
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN)
|
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN)
|
||||||
// exclude the core cordapp
|
// exclude the core cordapp
|
||||||
val cordapp = loader.cordapps.filter { it.cordappClasses.contains("net.corda.core.internal.cordapp.CordappImpl")}.single()
|
val cordapp = loader.cordapps.single { it.cordappClasses.contains("net.corda.core.internal.cordapp.CordappImpl") }
|
||||||
assertThat(cordapp.info.targetPlatformVersion).isEqualTo(2)
|
assertThat(cordapp.info.targetPlatformVersion).isEqualTo(2)
|
||||||
assertThat(cordapp.info.minimumPlatformVersion).isEqualTo(2)
|
assertThat(cordapp.info.minimumPlatformVersion).isEqualTo(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `cordapp classloader does not load apps when their min platform version is greater than the platform version`() {
|
fun `cordapp classloader does not load apps when their min platform version is greater than the node platform version`() {
|
||||||
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!!
|
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-no-target.jar")!!
|
||||||
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 1))
|
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 1))
|
||||||
// exclude the core cordapp
|
// exclude the core cordapp
|
||||||
assertThat(loader.cordapps.size).isEqualTo(1)
|
assertThat(loader.cordapps).hasSize(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -155,7 +153,7 @@ class JarScanningCordappLoaderTest {
|
|||||||
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!!
|
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!!
|
||||||
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 1000))
|
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 1000))
|
||||||
// exclude the core cordapp
|
// exclude the core cordapp
|
||||||
assertThat(loader.cordapps.size).isEqualTo(2)
|
assertThat(loader.cordapps).hasSize(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -163,11 +161,10 @@ class JarScanningCordappLoaderTest {
|
|||||||
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!!
|
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!!
|
||||||
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 2))
|
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 2))
|
||||||
// exclude the core cordapp
|
// exclude the core cordapp
|
||||||
assertThat(loader.cordapps.size).isEqualTo(2)
|
assertThat(loader.cordapps).hasSize(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun cordappLoaderForPackages(packages: Iterable<String>, versionInfo: VersionInfo = VersionInfo.UNKNOWN): CordappLoader {
|
private fun cordappLoaderForPackages(packages: Iterable<String>): CordappLoader {
|
||||||
|
|
||||||
val cordapps = cordappsForPackages(packages)
|
val cordapps = cordappsForPackages(packages)
|
||||||
return testDirectory().let { directory ->
|
return testDirectory().let { directory ->
|
||||||
cordapps.packageInDirectory(directory)
|
cordapps.packageInDirectory(directory)
|
||||||
@ -176,7 +173,6 @@ class JarScanningCordappLoaderTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun testDirectory(): Path {
|
private fun testDirectory(): Path {
|
||||||
|
|
||||||
return Paths.get("build", getTimestampAsDirectoryName())
|
return Paths.get("build", getTimestampAsDirectoryName())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user