CORDA-1355: Introduce a dedicated property which controls what is going to be in scope for classpath scanning (#2977)

* CORDA-1355: Introduce a dedicated property which controls what is going to be in scope for classpath scanning

* CORDA-1355: Update change log

* CORDA-1355: Minor change to improve readability.

* CORDA-1355: Custom serializers documentation update to mention new system property.
This commit is contained in:
Viktor Kolomeyko 2018-04-23 13:55:40 +01:00 committed by GitHub
parent bf4d8ba08c
commit 3aaa176dd4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 57 additions and 12 deletions

View File

@ -53,6 +53,8 @@ Unreleased
* java.math.BigInteger serialization support added.
* Fix CORDA-1355: Reduce amount of classpath scanning during integration tests execution.
.. _changelog_v3.1:
Version 3.1

View File

@ -17,11 +17,16 @@ Custom serializer classes should follow the rules for including classes found in
Writing a Custom Serializer
---------------------------
Serializers must
* Inherit from net.corda.core.serialization.SerializationCustomSerializer
* Inherit from ``net.corda.core.serialization.SerializationCustomSerializer``
* Provide a proxy class to transform the object to and from
* Implement the ``toProxy`` and ``fromProxy`` methods
* Be either included into CorDapp Jar or made known to the running process via ``amqp.custom.serialization.scanSpec``
system property.
This system property may be necessary to be able to discover custom serializer in the classpath. At a minimum the value
of the property should include comma separated set of packages where custom serializers located. Full syntax includes
scanning specification as defined by: `<http://github.com/lukehutch/fast-classpath-scanner/wiki/2.-Constructor#scan-spec>`
Serializers inheriting from SerializationCustomSerializer have to implement two methods and two types.
Serializers inheriting from ``SerializationCustomSerializer`` have to implement two methods and two types.
Example
-------

View File

@ -41,16 +41,26 @@ abstract class AbstractAMQPSerializationScheme(
// TODO: This method of initialisation for the Whitelist and plugin serializers will have to change
// when we have per-cordapp contexts and dynamic app reloading but for now it's the easiest way
companion object {
const val SCAN_SPEC_PROP_NAME = "amqp.custom.serialization.scanSpec"
private val serializationWhitelists: List<SerializationWhitelist> by lazy {
ServiceLoader.load(SerializationWhitelist::class.java, this::class.java.classLoader).toList() + DefaultWhitelist
}
private val customSerializers: List<SerializationCustomSerializer<*, *>> by lazy {
FastClasspathScanner().addClassLoader(this::class.java.classLoader).scan()
.getNamesOfClassesImplementing(SerializationCustomSerializer::class.java)
.mapNotNull { this::class.java.classLoader.loadClass(it).asSubclass(SerializationCustomSerializer::class.java) }
.filterNot { Modifier.isAbstract(it.modifiers) }
.map { it.kotlin.objectOrNewInstance() }
val scanSpec: String? = System.getProperty(SCAN_SPEC_PROP_NAME)
if(scanSpec == null) {
emptyList()
} else {
FastClasspathScanner(scanSpec).addClassLoader(this::class.java.classLoader).scan()
.getNamesOfClassesImplementing(SerializationCustomSerializer::class.java)
.mapNotNull { this::class.java.classLoader.loadClass(it).asSubclass(SerializationCustomSerializer::class.java) }
.filterNot { Modifier.isAbstract(it.modifiers) }
.map { it.kotlin.objectOrNewInstance() }
}
}
}

View File

@ -2,7 +2,9 @@ package net.corda.vega
import com.opengamma.strata.product.common.BuySell
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.packageName
import net.corda.core.utilities.getOrThrow
import net.corda.nodeapi.internal.serialization.amqp.AbstractAMQPSerializationScheme
import net.corda.testing.core.DUMMY_BANK_A_NAME
import net.corda.testing.core.DUMMY_BANK_B_NAME
import net.corda.testing.driver.DriverParameters
@ -12,7 +14,10 @@ import net.corda.vega.api.PortfolioApi
import net.corda.vega.api.PortfolioApiUtils
import net.corda.vega.api.SwapDataModel
import net.corda.vega.api.SwapDataView
import net.corda.vega.plugin.customserializers.CurrencyParameterSensitivitiesSerializer
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Test
import java.math.BigDecimal
import java.time.LocalDate
@ -26,6 +31,16 @@ class SimmValuationTest {
val testTradeId = "trade1"
}
@Before
fun setup() {
System.setProperty(AbstractAMQPSerializationScheme.SCAN_SPEC_PROP_NAME, CurrencyParameterSensitivitiesSerializer::class.packageName)
}
@After
fun tearDown() {
System.clearProperty(AbstractAMQPSerializationScheme.SCAN_SPEC_PROP_NAME)
}
@Test
fun `runs SIMM valuation demo`() {
driver(DriverParameters(isDebug = true, extraCordappPackagesToScan = listOf("net.corda.vega.contracts", "net.corda.vega.plugin.customserializers"))) {

View File

@ -39,6 +39,7 @@ import net.corda.nodeapi.internal.crypto.X509KeyStore
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.network.NetworkParametersCopier
import net.corda.nodeapi.internal.network.NodeInfoFilesCopier
import net.corda.nodeapi.internal.serialization.amqp.AbstractAMQPSerializationScheme
import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.DUMMY_BANK_A_NAME
@ -755,10 +756,11 @@ class DriverDSLImpl(
val systemProperties = mutableMapOf(
"name" to config.corda.myLegalName,
"visualvm.display.name" to "corda-${config.corda.myLegalName}",
"java.io.tmpdir" to System.getProperty("java.io.tmpdir"), // Inherit from parent process
"log4j2.debug" to if (debugPort != null) "true" else "false"
)
systemProperties += inheritFromParentProcess()
if (cordappPackages.isNotEmpty()) {
systemProperties += Node.scanPackagesSystemProperty to cordappPackages.joinToString(Node.scanPackagesSeparator)
}
@ -802,15 +804,26 @@ class DriverDSLImpl(
className = className, // cannot directly get class for this, so just use string
arguments = listOf("--base-directory", handle.baseDirectory.toString()),
jdwpPort = debugPort,
extraJvmArguments = listOf(
"-Dname=node-${handle.p2pAddress}-webserver",
"-Djava.io.tmpdir=${System.getProperty("java.io.tmpdir")}" // Inherit from parent process
),
extraJvmArguments = listOf("-Dname=node-${handle.p2pAddress}-webserver") +
inheritFromParentProcess().map { "-D${it.first}=${it.second}" },
workingDirectory = null,
maximumHeapSize = maximumHeapSize
)
}
private val propertiesInScope = setOf("java.io.tmpdir", AbstractAMQPSerializationScheme.SCAN_SPEC_PROP_NAME)
private fun inheritFromParentProcess() : Iterable<Pair<String, String>> {
return propertiesInScope.flatMap { propName ->
val propValue : String? = System.getProperty(propName)
if(propValue == null) {
emptySet()
} else {
setOf(Pair(propName, propValue))
}
}
}
private fun NodeHandleInternal.toWebServerConfig(): Config {
var config = ConfigFactory.empty()