Safe parsing of min platform version and target version from CorDapp MANIFEST files (#4031)

Also includes some cleanup
This commit is contained in:
Shams Asari 2018-10-04 16:00:07 +01:00 committed by GitHub
parent 064c72dfb1
commit 85d2a85e85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 39 deletions

View File

@ -42,8 +42,7 @@ data class 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) {
companion object {
private const val UNKNOWN_VALUE = "Unknown"
const val UNKNOWN_VALUE = "Unknown"
val UNKNOWN = Info(UNKNOWN_VALUE, UNKNOWN_VALUE, UNKNOWN_VALUE, 1, 1)
}

View File

@ -112,10 +112,12 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
)
private fun loadCordapps(): List<CordappImpl> {
val cordapps = cordappJarPaths.map { scanCordapp(it).toCordapp(it) }
val cordapps = cordappJarPaths
.map { scanCordapp(it).toCordapp(it) }
.filter {
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
} else {
true
@ -126,7 +128,7 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
}
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(
findContractClassNames(this),
findInitiatedFlows(this),

View File

@ -1,6 +1,7 @@
package net.corda.node.internal.cordapp
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.Manifest
@ -23,23 +24,23 @@ fun createTestManifest(name: String, title: String, version: String, vendor: Str
return manifest
}
operator fun Manifest.set(key: String, value: String) {
mainAttributes.putValue(key, value)
operator fun Manifest.set(key: String, value: String): String? {
return mainAttributes.putValue(key, value)
}
fun Manifest?.toCordappInfo(defaultShortName: String): CordappImpl.Info {
var info = CordappImpl.Info.UNKNOWN
(this?.mainAttributes?.getValue("Name") ?: defaultShortName).let { shortName ->
info = info.copy(shortName = shortName)
}
this?.mainAttributes?.getValue("Implementation-Vendor")?.let { vendor ->
info = info.copy(vendor = vendor)
}
this?.mainAttributes?.getValue("Implementation-Version")?.let { version ->
info = info.copy(version = version)
}
val minPlatformVersion = this?.mainAttributes?.getValue("Min-Platform-Version")?.toInt() ?: 1
val targetPlatformVersion = this?.mainAttributes?.getValue("Target-Platform-Version")?.toInt() ?: minPlatformVersion
info = info.copy(minimumPlatformVersion = minPlatformVersion, targetPlatformVersion = targetPlatformVersion)
return info
}
operator fun Manifest.get(key: String): String? = mainAttributes.getValue(key)
fun Manifest.toCordappInfo(defaultShortName: String): CordappImpl.Info {
val shortName = this["Name"] ?: defaultShortName
val vendor = this["Implementation-Vendor"] ?: UNKNOWN_VALUE
val version = this["Implementation-Version"] ?: UNKNOWN_VALUE
val minPlatformVersion = this["Min-Platform-Version"]?.toIntOrNull() ?: 1
val targetPlatformVersion = this["Target-Platform-Version"]?.toIntOrNull() ?: minPlatformVersion
return CordappImpl.Info(
shortName = shortName,
vendor = vendor,
version = version,
minimumPlatformVersion = minPlatformVersion,
targetPlatformVersion = targetPlatformVersion
)
}

View File

@ -4,7 +4,6 @@ import co.paralleluniverse.fibers.Suspendable
import net.corda.core.flows.*
import net.corda.node.VersionInfo
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.getTimestampAsDirectoryName
import net.corda.testing.node.internal.packageInDirectory
@ -45,7 +44,7 @@ class JarScanningCordappLoaderTest {
}
@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
val loader = JarScanningCordappLoader.fromDirectories(listOf(Paths.get(".")))
assertThat(loader.cordapps).containsOnly(loader.coreCordapp)
@ -56,10 +55,9 @@ class JarScanningCordappLoaderTest {
val isolatedJAR = JarScanningCordappLoaderTest::class.java.getResource("isolated.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(isolatedJAR))
val actual = loader.cordapps.toTypedArray()
assertThat(actual).hasSize(2)
assertThat(loader.cordapps).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.initiatedFlows.single().name).isEqualTo("net.corda.finance.contracts.isolated.IsolatedDummyFlow\$Acceptor")
assertThat(actualCordapp.rpcFlows).isEmpty()
@ -113,7 +111,7 @@ class JarScanningCordappLoaderTest {
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 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.minimumPlatformVersion).isEqualTo(1)
}
@ -126,7 +124,7 @@ class JarScanningCordappLoaderTest {
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN)
// 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.minimumPlatformVersion).isEqualTo(2)
}
@ -137,17 +135,17 @@ class JarScanningCordappLoaderTest {
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-no-target.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN)
// 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.minimumPlatformVersion).isEqualTo(2)
}
@Test
fun `cordapp classloader does not load apps when their min platform version is greater than the platform version`() {
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!!
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-no-target.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 1))
// exclude the core cordapp
assertThat(loader.cordapps.size).isEqualTo(1)
assertThat(loader.cordapps).hasSize(1)
}
@Test
@ -155,7 +153,7 @@ class JarScanningCordappLoaderTest {
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 1000))
// exclude the core cordapp
assertThat(loader.cordapps.size).isEqualTo(2)
assertThat(loader.cordapps).hasSize(2)
}
@Test
@ -163,11 +161,10 @@ class JarScanningCordappLoaderTest {
val jar = JarScanningCordappLoaderTest::class.java.getResource("versions/min-2-target-3.jar")!!
val loader = JarScanningCordappLoader.fromJarUrls(listOf(jar), VersionInfo.UNKNOWN.copy(platformVersion = 2))
// 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)
return testDirectory().let { directory ->
cordapps.packageInDirectory(directory)
@ -176,7 +173,6 @@ class JarScanningCordappLoaderTest {
}
private fun testDirectory(): Path {
return Paths.get("build", getTimestampAsDirectoryName())
}
}