ENT-11090: Removed all JDK 8/11 conditional code

This commit is contained in:
Shams Asari 2024-03-01 17:23:23 +00:00
parent 6bdad94236
commit 900809b3d7
21 changed files with 78 additions and 183 deletions

View File

@ -259,7 +259,6 @@ allprojects {
targetCompatibility = VERSION_17 targetCompatibility = VERSION_17
jacoco { jacoco {
// JDK11 official support (https://github.com/jacoco/jacoco/releases/tag/v0.8.3)
toolVersion = "0.8.7" toolVersion = "0.8.7"
} }

View File

@ -120,7 +120,7 @@ open class StringToMethodCallParser<in T : Any> @JvmOverloads constructor(
} }
/** /**
* Uses either Kotlin or Java 8 reflection to learn the names of the parameters to a method. * Uses either Kotlin or Java reflection to learn the names of the parameters to a method.
*/ */
open fun paramNamesFromMethod(method: Method): List<String> { open fun paramNamesFromMethod(method: Method): List<String> {
val kf: KFunction<*>? = method.kotlinFunction val kf: KFunction<*>? = method.kotlinFunction
@ -135,7 +135,7 @@ open class StringToMethodCallParser<in T : Any> @JvmOverloads constructor(
} }
/** /**
* Uses either Kotlin or Java 8 reflection to learn the names of the parameters to a constructor. * Uses either Kotlin or Java reflection to learn the names of the parameters to a constructor.
*/ */
open fun paramNamesFromConstructor(ctor: Constructor<*>): List<String> { open fun paramNamesFromConstructor(ctor: Constructor<*>): List<String> {
val kf: KFunction<*>? = ctor.kotlinFunction val kf: KFunction<*>? = ctor.kotlinFunction

View File

@ -17,7 +17,6 @@ platformVersion=140
openTelemetryVersion=1.20.1 openTelemetryVersion=1.20.1
openTelemetrySemConvVersion=1.20.1-alpha openTelemetrySemConvVersion=1.20.1-alpha
guavaVersion=28.0-jre guavaVersion=28.0-jre
# Quasar version to use with Java 8:
quasarVersion=0.9.0_r3 quasarVersion=0.9.0_r3
dockerJavaVersion=3.2.5 dockerJavaVersion=3.2.5
proguardVersion=7.3.1 proguardVersion=7.3.1

View File

@ -58,7 +58,6 @@ dependencies {
testImplementation "org.bouncycastle:bcpkix-jdk18on:$bouncycastle_version" testImplementation "org.bouncycastle:bcpkix-jdk18on:$bouncycastle_version"
testImplementation "org.ow2.asm:asm:$asm_version" testImplementation "org.ow2.asm:asm:$asm_version"
// JDK11: required by Quasar at run-time
testRuntimeOnly "com.esotericsoftware:kryo:$kryo_version" testRuntimeOnly "com.esotericsoftware:kryo:$kryo_version"
testRuntimeOnly "org.slf4j:slf4j-simple:$slf4j_version" testRuntimeOnly "org.slf4j:slf4j-simple:$slf4j_version"

View File

@ -33,15 +33,12 @@ fun <T: Any> createInstancesOfClassesImplementing(classloader: ClassLoader, claz
* @return names of the identified classes. * @return names of the identified classes.
* @throws UnsupportedClassVersionError if the class version is not within range. * @throws UnsupportedClassVersionError if the class version is not within range.
*/ */
fun <T: Any> getNamesOfClassesImplementing(classloader: ClassLoader, clazz: Class<T>, fun <T: Any> getNamesOfClassesImplementing(classloader: ClassLoader, clazz: Class<T>, classVersionRange: IntRange? = null): Set<String> {
classVersionRange: IntRange? = null): Set<String> { val classGraph = ClassGraph()
val isJava11 = JavaVersion.isVersionAtLeast(JavaVersion.Java_11) if (classloader !== ClassLoader.getSystemClassLoader()) {
classGraph.overrideClassLoaders(classloader)
return ClassGraph().apply {
if (!isJava11 || classloader !== ClassLoader.getSystemClassLoader()) {
overrideClassLoaders(classloader)
}
} }
return classGraph
.enableURLScheme(attachmentScheme) .enableURLScheme(attachmentScheme)
.ignoreParentClassLoaders() .ignoreParentClassLoaders()
.enableClassInfo() .enableClassInfo()

View File

@ -1,4 +1,4 @@
@file:Suppress("TooManyFunctions") @file:Suppress("MatchingDeclarationName")
package net.corda.core.internal package net.corda.core.internal
import net.corda.core.contracts.ContractClassName import net.corda.core.contracts.ContractClassName
@ -36,24 +36,6 @@ fun checkMinimumPlatformVersion(minimumPlatformVersion: Int, requiredMinPlatform
} }
} }
// JDK11: revisit (JDK 9+ uses different numbering scheme: see https://docs.oracle.com/javase/9/docs/api/java/lang/Runtime.Version.html)
@Throws(NumberFormatException::class)
fun getJavaUpdateVersion(javaVersion: String): Long = javaVersion.substringAfter("_").substringBefore("-").toLong()
enum class JavaVersion(val versionString: String) {
Java_1_8("1.8"),
Java_11("11");
companion object {
fun isVersionAtLeast(version: JavaVersion): Boolean {
return currentVersion.toFloat() >= version.versionString.toFloat()
}
private val currentVersion: String = System.getProperty("java.specification.version") ?:
throw IllegalStateException("Unable to retrieve system property java.specification.version")
}
}
/** Checks if this flow is an idempotent flow. */ /** Checks if this flow is an idempotent flow. */
fun Class<out FlowLogic<*>>.isIdempotentFlow(): Boolean { fun Class<out FlowLogic<*>>.isIdempotentFlow(): Boolean {
return IdempotentFlow::class.java.isAssignableFrom(this) return IdempotentFlow::class.java.isAssignableFrom(this)

View File

@ -61,7 +61,6 @@ dependencies {
runtimeOnly 'com.mattbertolini:liquibase-slf4j:2.0.0' runtimeOnly 'com.mattbertolini:liquibase-slf4j:2.0.0'
// JDK11: required by Quasar at run-time
runtimeOnly "com.esotericsoftware:kryo:$kryo_version" runtimeOnly "com.esotericsoftware:kryo:$kryo_version"
testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version" testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version"

View File

@ -19,11 +19,3 @@ object CordaClosureSerializer : ClosureSerializer() {
return target is Serializable return target is Serializable
} }
} }
object CordaClosureBlacklistSerializer : ClosureSerializer() {
const val ERROR_MESSAGE = "Java 8 Lambda expressions are not supported for serialization."
override fun write(kryo: Kryo, output: Output, target: Any) {
throw IllegalArgumentException(ERROR_MESSAGE)
}
}

View File

@ -6,8 +6,6 @@ import com.esotericsoftware.kryo.KryoSerializable
import com.esotericsoftware.kryo.io.Input import com.esotericsoftware.kryo.io.Input
import com.esotericsoftware.kryo.io.Output import com.esotericsoftware.kryo.io.Output
import com.google.common.primitives.Ints import com.google.common.primitives.Ints
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.whenever
import net.corda.core.contracts.PrivacySalt import net.corda.core.contracts.PrivacySalt
import net.corda.core.contracts.SignatureAttachmentConstraint import net.corda.core.contracts.SignatureAttachmentConstraint
import net.corda.core.crypto.Crypto import net.corda.core.crypto.Crypto
@ -37,8 +35,6 @@ import net.corda.serialization.internal.encodingNotPermittedFormat
import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.TestIdentity import net.corda.testing.core.TestIdentity
import net.corda.testing.core.internal.CheckpointSerializationEnvironmentRule import net.corda.testing.core.internal.CheckpointSerializationEnvironmentRule
import org.apache.commons.lang3.JavaVersion
import org.apache.commons.lang3.SystemUtils
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy import org.assertj.core.api.Assertions.assertThatThrownBy
import org.assertj.core.api.Assertions.catchThrowable import org.assertj.core.api.Assertions.catchThrowable
@ -50,6 +46,8 @@ import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.junit.runners.Parameterized import org.junit.runners.Parameterized
import org.junit.runners.Parameterized.Parameters import org.junit.runners.Parameterized.Parameters
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.whenever
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.io.InputStream import java.io.InputStream
import java.time.Instant import java.time.Instant
@ -67,7 +65,7 @@ class KryoTests(private val compression: CordaSerializationEncoding?) {
private val ALICE_PUBKEY = TestIdentity(ALICE_NAME, 70).publicKey private val ALICE_PUBKEY = TestIdentity(ALICE_NAME, 70).publicKey
@Parameters(name = "{0}") @Parameters(name = "{0}")
@JvmStatic @JvmStatic
fun compression() = arrayOf<CordaSerializationEncoding?>(null) + CordaSerializationEncoding.values() fun compression(): List<CordaSerializationEncoding?> = CordaSerializationEncoding.entries + null
} }
@get:Rule @get:Rule
@ -399,11 +397,7 @@ class KryoTests(private val compression: CordaSerializationEncoding?) {
val obj = Holder(ByteArray(20000)) val obj = Holder(ByteArray(20000))
val uncompressedSize = obj.checkpointSerialize(context.withEncoding(null)).size val uncompressedSize = obj.checkpointSerialize(context.withEncoding(null)).size
val compressedSize = obj.checkpointSerialize(context.withEncoding(CordaSerializationEncoding.SNAPPY)).size val compressedSize = obj.checkpointSerialize(context.withEncoding(CordaSerializationEncoding.SNAPPY)).size
// If these need fixing, sounds like Kryo wire format changed and checkpoints might not survive an upgrade.
if (SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_11))
assertEquals(20127, uncompressedSize) assertEquals(20127, uncompressedSize)
else
assertEquals(20234, uncompressedSize)
assertEquals(1095, compressedSize) assertEquals(1095, compressedSize)
} }
} }

View File

@ -3,7 +3,6 @@ package net.corda.node.amqp
import org.mockito.kotlin.doReturn import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever import org.mockito.kotlin.whenever
import net.corda.core.internal.JavaVersion
import net.corda.core.toFuture import net.corda.core.toFuture
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.contextLogger import net.corda.core.utilities.contextLogger
@ -23,8 +22,8 @@ import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.BOB_NAME import net.corda.testing.core.BOB_NAME
import net.corda.testing.driver.internal.incrementalPortAllocation import net.corda.testing.driver.internal.incrementalPortAllocation
import net.corda.testing.internal.fixedCrlSource import net.corda.testing.internal.fixedCrlSource
import org.junit.Assume.assumeFalse
import org.junit.Before import org.junit.Before
import org.junit.Ignore
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.rules.TemporaryFolder import org.junit.rules.TemporaryFolder
@ -43,6 +42,7 @@ import kotlin.test.assertTrue
* *
* In order to have control over handshake internals a simple TLS server is created which may have a configurable handshake delay. * In order to have control over handshake internals a simple TLS server is created which may have a configurable handshake delay.
*/ */
@Ignore // These tests were disabled for JDK11+ very shortly after being introduced (https://github.com/corda/corda/pull/6560)
@RunWith(Parameterized::class) @RunWith(Parameterized::class)
class AMQPClientSslErrorsTest(@Suppress("unused") private val iteration: Int) { class AMQPClientSslErrorsTest(@Suppress("unused") private val iteration: Int) {
@ -144,10 +144,7 @@ class AMQPClientSslErrorsTest(@Suppress("unused") private val iteration: Int) {
} }
@Test(timeout = 300_000) @Test(timeout = 300_000)
fun trivialClientServerExchange() { fun `trivial client server exchange`() {
// SSL works quite differently in JDK 11 and re-work is needed
assumeFalse(JavaVersion.isVersionAtLeast(JavaVersion.Java_11))
val serverPort = portAllocation.nextPort() val serverPort = portAllocation.nextPort()
val serverThread = ServerThread(serverKeyManagerFactory, serverTrustManagerFactory, serverPort).also { it.start() } val serverThread = ServerThread(serverKeyManagerFactory, serverTrustManagerFactory, serverPort).also { it.start() }
@ -182,10 +179,7 @@ class AMQPClientSslErrorsTest(@Suppress("unused") private val iteration: Int) {
} }
@Test(timeout = 300_000) @Test(timeout = 300_000)
fun amqpClientServerConnect() { fun `amqp client server connect`() {
// SSL works quite differently in JDK 11 and re-work is needed
assumeFalse(JavaVersion.isVersionAtLeast(JavaVersion.Java_11))
val serverPort = portAllocation.nextPort() val serverPort = portAllocation.nextPort()
val serverThread = ServerThread(serverKeyManagerFactory, serverTrustManagerFactory, serverPort) val serverThread = ServerThread(serverKeyManagerFactory, serverTrustManagerFactory, serverPort)
.also { it.start() } .also { it.start() }
@ -205,10 +199,7 @@ class AMQPClientSslErrorsTest(@Suppress("unused") private val iteration: Int) {
} }
@Test(timeout = 300_000) @Test(timeout = 300_000)
fun amqpClientServerHandshakeTimeout() { fun `amqp client server handshake timeout`() {
// SSL works quite differently in JDK 11 and re-work is needed
assumeFalse(JavaVersion.isVersionAtLeast(JavaVersion.Java_11))
val serverPort = portAllocation.nextPort() val serverPort = portAllocation.nextPort()
val serverThread = ServerThread(serverKeyManagerFactory, serverTrustManagerFactory, serverPort, 5.seconds) val serverThread = ServerThread(serverKeyManagerFactory, serverTrustManagerFactory, serverPort, 5.seconds)
.also { it.start() } .also { it.start() }

View File

@ -1155,9 +1155,6 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
return NodeVaultService(platformClock, keyManagementService, services, database, schemaService, cordappLoader.appClassLoader) return NodeVaultService(platformClock, keyManagementService, services, database, schemaService, cordappLoader.appClassLoader)
} }
// JDK 11: switch to directly instantiating jolokia server (rather than indirectly via dynamically self attaching Java Agents,
// which is no longer supported from JDK 9 onwards (https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8180425).
// No longer need to use https://github.com/electronicarts/ea-agent-loader either (which is also deprecated)
private fun initialiseJolokia() { private fun initialiseJolokia() {
configuration.jmxMonitoringHttpPort?.let { port -> configuration.jmxMonitoringHttpPort?.let { port ->
val config = JolokiaServerConfig(mapOf("port" to port.toString())) val config = JolokiaServerConfig(mapOf("port" to port.toString()))

View File

@ -17,7 +17,6 @@ import net.corda.core.internal.Emoji
import net.corda.core.internal.concurrent.openFuture import net.corda.core.internal.concurrent.openFuture
import net.corda.core.internal.concurrent.thenMatch import net.corda.core.internal.concurrent.thenMatch
import net.corda.core.internal.errors.AddressBindingException import net.corda.core.internal.errors.AddressBindingException
import net.corda.core.internal.getJavaUpdateVersion
import net.corda.core.internal.notary.NotaryService import net.corda.core.internal.notary.NotaryService
import net.corda.core.messaging.RPCOps import net.corda.core.messaging.RPCOps
import net.corda.core.node.NetworkParameters import net.corda.core.node.NetworkParameters
@ -170,7 +169,7 @@ open class Node(configuration: NodeConfiguration,
fun isInvalidJavaVersion(): Boolean { fun isInvalidJavaVersion(): Boolean {
if (!hasMinimumJavaVersion()) { if (!hasMinimumJavaVersion()) {
println("You are using a version of Java that is not supported (${SystemUtils.JAVA_VERSION}). Please upgrade to the latest version of Java 8.") println("You are using a version of Java that is not supported (${SystemUtils.JAVA_VERSION}). Please upgrade to the latest version of Java 17.")
println("Corda will now exit...") println("Corda will now exit...")
return true return true
} }
@ -178,17 +177,7 @@ open class Node(configuration: NodeConfiguration,
} }
private fun hasMinimumJavaVersion(): Boolean { private fun hasMinimumJavaVersion(): Boolean {
// JDK 11: review naming convention and checking of 'minUpdateVersion' and 'distributionType` (OpenJDK, Oracle, Zulu, AdoptOpenJDK, Cornetto) return SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_17)
return try {
if (SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_11))
return true
else {
val update = getJavaUpdateVersion(SystemUtils.JAVA_VERSION) // To filter out cases like 1.8.0_202-ea
(SystemUtils.IS_JAVA_1_8 && update >= 171)
}
} catch (e: NumberFormatException) { // custom JDKs may not have the update version (e.g. 1.8.0-adoptopenjdk)
false
}
} }
} }

View File

@ -279,8 +279,6 @@ open class NodeStartup : NodeStartupLogging {
logger.info("PID: ${ProcessHandle.current().pid()}") logger.info("PID: ${ProcessHandle.current().pid()}")
logger.info("Main class: ${NodeConfiguration::class.java.location.toURI().path}") logger.info("Main class: ${NodeConfiguration::class.java.location.toURI().path}")
logger.info("CommandLine Args: ${info.inputArguments.joinToString(" ")}") logger.info("CommandLine Args: ${info.inputArguments.joinToString(" ")}")
// JDK 11 (bootclasspath no longer supported from JDK 9)
if (info.isBootClassPathSupported) logger.info("bootclasspath: ${info.bootClassPath}")
logger.info("classpath: ${info.classPath}") logger.info("classpath: ${info.classPath}")
logger.info("VM ${info.vmName} ${info.vmVendor} ${info.vmVersion}") logger.info("VM ${info.vmName} ${info.vmVendor} ${info.vmVersion}")
logger.info("Machine: ${lookupMachineNameAndMaybeWarn()}") logger.info("Machine: ${lookupMachineNameAndMaybeWarn()}")

View File

@ -111,7 +111,7 @@ class NodeSchedulerService(private val clock: CordaClock,
} }
/** /**
* Convert a Guava [ListenableFuture] or JDK8 [CompletableFuture] to Quasar implementation and set to true when a result * Convert a Guava [ListenableFuture] or JDK [CompletableFuture] to Quasar implementation and set to true when a result
* or [Throwable] is available in the original. * or [Throwable] is available in the original.
* *
* We need this so that we do not block the actual thread when calling get(), but instead allow a Quasar context * We need this so that we do not block the actual thread when calling get(), but instead allow a Quasar context

View File

@ -213,7 +213,7 @@ class FlowCreator(
} }
private fun verifyFlowLogicIsSuspendable(logic: FlowLogic<Any?>) { private fun verifyFlowLogicIsSuspendable(logic: FlowLogic<Any?>) {
// Quasar requires (in Java 8) that at least the call method be annotated suspendable. Unfortunately, it's // Quasar requires that at least the call method be annotated suspendable. Unfortunately, it's
// easy to forget to add this when creating a new flow, so we check here to give the user a better error. // easy to forget to add this when creating a new flow, so we check here to give the user a better error.
// //
// The Kotlin compiler can sometimes generate a synthetic bridge method from a single call declaration, which // The Kotlin compiler can sometimes generate a synthetic bridge method from a single call declaration, which

View File

@ -1,7 +1,6 @@
package net.corda.node.internal package net.corda.node.internal
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.getJavaUpdateVersion
import net.corda.core.internal.readObject import net.corda.core.internal.readObject
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
@ -25,7 +24,6 @@ import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.internal.configureDatabase import net.corda.testing.internal.configureDatabase
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.Ignore
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.rules.TemporaryFolder import org.junit.rules.TemporaryFolder
@ -38,7 +36,6 @@ import kotlin.io.path.deleteExisting
import kotlin.io.path.name import kotlin.io.path.name
import kotlin.io.path.useDirectoryEntries import kotlin.io.path.useDirectoryEntries
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertNull import kotlin.test.assertNull
class NodeTest { class NodeTest {
@ -141,11 +138,11 @@ class NodeTest {
serial = nodeInfo1.serial serial = nodeInfo1.serial
) )
configureDatabase(configuration.dataSourceProperties, configuration.database, { null }, { null }).use { configureDatabase(configuration.dataSourceProperties, configuration.database, { null }, { null }).use { persistence ->
it.transaction { persistence.transaction {
session.save(persistentNodeInfo1) session.save(persistentNodeInfo1)
} }
it.transaction { persistence.transaction {
session.save(persistentNodeInfo2) session.save(persistentNodeInfo2)
} }
@ -160,16 +157,6 @@ class NodeTest {
} }
} }
// JDK11: revisit (JDK 9+ uses different numbering scheme: see https://docs.oracle.com/javase/9/docs/api/java/lang/Runtime.Version.html)
@Ignore
@Test(timeout=300_000)
fun `test getJavaUpdateVersion`() {
assertThat(getJavaUpdateVersion("1.8.0_202-ea")).isEqualTo(202)
assertThat(getJavaUpdateVersion("1.8.0_202")).isEqualTo(202)
assertFailsWith<NumberFormatException> { getJavaUpdateVersion("1.8.0_202wrong-format") }
assertFailsWith<NumberFormatException> { getJavaUpdateVersion("1.8.0-adoptopenjdk") }
}
private fun getAllInfos(database: CordaPersistence): List<NodeInfoSchemaV1.PersistentNodeInfo> { private fun getAllInfos(database: CordaPersistence): List<NodeInfoSchemaV1.PersistentNodeInfo> {
return database.transaction { return database.transaction {
val criteria = session.criteriaBuilder.createQuery(NodeInfoSchemaV1.PersistentNodeInfo::class.java) val criteria = session.criteriaBuilder.createQuery(NodeInfoSchemaV1.PersistentNodeInfo::class.java)

View File

@ -1,6 +1,5 @@
package net.corda.node.utilities package net.corda.node.utilities
import co.paralleluniverse.fibers.FiberExecutorScheduler import co.paralleluniverse.fibers.FiberExecutorScheduler
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import co.paralleluniverse.strands.Strand import co.paralleluniverse.strands.Strand
@ -12,6 +11,7 @@ import net.corda.node.CordaClock
import net.corda.node.SimpleClock import net.corda.node.SimpleClock
import net.corda.node.services.events.NodeSchedulerService import net.corda.node.services.events.NodeSchedulerService
import net.corda.testing.node.TestClock import net.corda.testing.node.TestClock
import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -22,13 +22,11 @@ import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors import java.util.concurrent.Executors
import kotlin.test.assertFalse import kotlin.test.assertFalse
import kotlin.test.assertTrue import kotlin.test.assertTrue
import kotlin.test.fail
class ClockUtilsTest { class ClockUtilsTest {
private lateinit var realClock: Clock
lateinit var realClock: Clock private lateinit var stoppedClock: CordaClock
lateinit var stoppedClock: CordaClock private lateinit var executor: ExecutorService
lateinit var executor: ExecutorService
@Before @Before
fun setup() { fun setup() {
@ -133,31 +131,29 @@ class ClockUtilsTest {
val testClock = TestClock(stoppedClock) val testClock = TestClock(stoppedClock)
val advancedClock = Clock.offset(stoppedClock, 10.hours) val advancedClock = Clock.offset(stoppedClock, 10.hours)
try { assertThatExceptionOfType(InterruptedException::class.java).isThrownBy {
NodeSchedulerService.awaitWithDeadline(testClock, advancedClock.instant(), SettableFuture.create<Boolean>()) NodeSchedulerService.awaitWithDeadline(testClock, advancedClock.instant(), SettableFuture.create<Boolean>())
fail("Expected InterruptedException")
} catch (exception: InterruptedException) {
} }
} }
@Test(timeout=300_000) @Test(timeout=300_000)
@Suspendable @Suspendable
fun `test waiting for a deadline with multiple clock advance and incomplete JDK8 future on Fibers`() { fun `test waiting for a deadline with multiple clock advance and incomplete JDK future on Fibers`() {
val advancedClock = Clock.offset(stoppedClock, 1.hours) val advancedClock = Clock.offset(stoppedClock, 1.hours)
val testClock = TestClock(stoppedClock) val testClock = TestClock(stoppedClock)
val future = CompletableFuture<Boolean>() val future = CompletableFuture<Boolean>()
val scheduler = FiberExecutorScheduler("test", executor) val scheduler = FiberExecutorScheduler("test", executor)
val fiber = scheduler.newFiber(@Suspendable { val fiber = scheduler.newFiber @Suspendable {
future.complete(NodeSchedulerService.awaitWithDeadline(testClock, advancedClock.instant(), future)) future.complete(NodeSchedulerService.awaitWithDeadline(testClock, advancedClock.instant(), future))
}).start() }.start()
for (advance in 1..6) { for (advance in 1..6) {
scheduler.newFiber(@Suspendable { scheduler.newFiber @Suspendable {
// Wait until fiber is waiting // Wait until fiber is waiting
while (fiber.state != Strand.State.TIMED_WAITING) { while (fiber.state != Strand.State.TIMED_WAITING) {
Strand.sleep(1) Strand.sleep(1)
} }
testClock.advanceBy(10.minutes) testClock.advanceBy(10.minutes)
}).start() }.start()
} }
assertFalse(future.getOrThrow(), "Should have reached deadline") assertFalse(future.getOrThrow(), "Should have reached deadline")
} }
@ -169,17 +165,17 @@ class ClockUtilsTest {
val testClock = TestClock(stoppedClock) val testClock = TestClock(stoppedClock)
val future = SettableFuture.create<Boolean>() val future = SettableFuture.create<Boolean>()
val scheduler = FiberExecutorScheduler("test", executor) val scheduler = FiberExecutorScheduler("test", executor)
val fiber = scheduler.newFiber(@Suspendable { val fiber = scheduler.newFiber @Suspendable {
future.set(NodeSchedulerService.awaitWithDeadline(testClock, advancedClock.instant(), future)) future.set(NodeSchedulerService.awaitWithDeadline(testClock, advancedClock.instant(), future))
}).start() }.start()
for (advance in 1..6) { for (advance in 1..6) {
scheduler.newFiber(@Suspendable { scheduler.newFiber @Suspendable {
// Wait until fiber is waiting // Wait until fiber is waiting
while (fiber.state != Strand.State.TIMED_WAITING) { while (fiber.state != Strand.State.TIMED_WAITING) {
Strand.sleep(1) Strand.sleep(1)
} }
testClock.advanceBy(10.minutes) testClock.advanceBy(10.minutes)
}).start() }.start()
} }
assertFalse(future.getOrThrow(), "Should have reached deadline") assertFalse(future.getOrThrow(), "Should have reached deadline")
} }

View File

@ -56,6 +56,7 @@ import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.assertj.core.api.Assertions.assertThatThrownBy import org.assertj.core.api.Assertions.assertThatThrownBy
import org.assertj.core.api.Assertions.catchThrowable import org.assertj.core.api.Assertions.catchThrowable
import org.assertj.core.api.Assumptions.assumeThat
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.cert.X509v2CRLBuilder import org.bouncycastle.cert.X509v2CRLBuilder
import org.bouncycastle.cert.jcajce.JcaX509CRLConverter import org.bouncycastle.cert.jcajce.JcaX509CRLConverter
@ -139,7 +140,7 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi
val MINI_CORP_PUBKEY get() = miniCorp.publicKey val MINI_CORP_PUBKEY get() = miniCorp.publicKey
@Parameters(name = "{0}") @Parameters(name = "{0}")
@JvmStatic @JvmStatic
fun compression() = arrayOf<CordaSerializationEncoding?>(null) + CordaSerializationEncoding.values() fun compression(): List<CordaSerializationEncoding?> = CordaSerializationEncoding.entries + null
} }
@Rule @Rule
@ -534,7 +535,7 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi
@Test(timeout=300_000) @Test(timeout=300_000)
fun `class constructor is invoked on deserialisation`() { fun `class constructor is invoked on deserialisation`() {
compression == null || return // Manipulation of serialized bytes is invalid if they're compressed. assumeThat(compression).isNull()
val serializerFactory = SerializerFactoryBuilder.build(AllWhitelist, val serializerFactory = SerializerFactoryBuilder.build(AllWhitelist,
ClassCarpenterImpl(AllWhitelist, ClassLoader.getSystemClassLoader()) ClassCarpenterImpl(AllWhitelist, ClassLoader.getSystemClassLoader())
) )
@ -641,7 +642,7 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi
private fun assertSerializedThrowableEquivalent(t: Throwable, desThrowable: Throwable) { private fun assertSerializedThrowableEquivalent(t: Throwable, desThrowable: Throwable) {
assertTrue(desThrowable is CordaRuntimeException) // Since we don't handle the other case(s) yet assertTrue(desThrowable is CordaRuntimeException) // Since we don't handle the other case(s) yet
assertEquals("${t.javaClass.name}: ${t.message}", desThrowable.message) assertEquals("${t.javaClass.name}: ${t.message}", desThrowable.message)
assertTrue(Objects.deepEquals(t.stackTrace.toStackTraceBasic, desThrowable.stackTrace.toStackTraceBasic)) assertTrue(Objects.deepEquals(t.stackTrace.map(::BasicStrackTraceElement), desThrowable.stackTrace.map(::BasicStrackTraceElement)))
assertEquals(t.suppressed.size, desThrowable.suppressed.size) assertEquals(t.suppressed.size, desThrowable.suppressed.size)
t.suppressed.zip(desThrowable.suppressed).forEach { (before, after) -> assertSerializedThrowableEquivalent(before, after) } t.suppressed.zip(desThrowable.suppressed).forEach { (before, after) -> assertSerializedThrowableEquivalent(before, after) }
} }
@ -1582,35 +1583,19 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi
assertEquals(1018, compressedSize) assertEquals(1018, compressedSize)
} }
// JDK11: backwards compatibility function to deal with StacktraceElement comparison pre-JPMS
private fun deepEquals(a: Any?, b: Any?): Boolean { private fun deepEquals(a: Any?, b: Any?): Boolean {
return if (a === b) return when {
true a is Throwable && b is Throwable -> BasicThrowable(a) == BasicThrowable(b)
else if (a == null || b == null) else -> Objects.deepEquals(a, b)
false
else {
if (a is Exception && b is Exception)
(a.cause == b.cause && a.localizedMessage == b.localizedMessage && a.message == b.message) &&
Objects.deepEquals(a.stackTrace.toStackTraceBasic, b.stackTrace.toStackTraceBasic)
else
Objects.deepEquals(a, b)
} }
} }
private val <T> Array<T>.toStackTraceBasic: Unit private data class BasicThrowable(val cause: BasicThrowable?, val message: String?, val stackTrace: List<BasicStrackTraceElement>) {
get() { constructor(t: Throwable) : this(t.cause?.let(::BasicThrowable), t.message, t.stackTrace.map(::BasicStrackTraceElement))
this.map { StackTraceElementBasic(it as StackTraceElement) }
} }
// JPMS adds additional fields that are not equal according to classloader/module hierarchy // JPMS adds additional fields that are not equal according to classloader/module hierarchy
data class StackTraceElementBasic(val ste: StackTraceElement) { private data class BasicStrackTraceElement(val className: String, val methodName: String, val fileName: String?, val lineNumber: Int) {
override fun equals(other: Any?): Boolean { constructor(ste: StackTraceElement) : this(ste.className, ste.methodName, ste.fileName, ste.lineNumber)
return if (other is StackTraceElementBasic)
(ste.className == other.ste.className) &&
(ste.methodName == other.ste.methodName) &&
(ste.fileName == other.ste.fileName) &&
(ste.lineNumber == other.ste.lineNumber)
else false
}
} }
} }

View File

@ -50,17 +50,11 @@ private class SetterCaller(val setter: Method) : (Any, Any?) -> Unit {
try { try {
setter.invoke(target, value) setter.invoke(target, value)
} catch (e: InvocationTargetException) { } catch (e: InvocationTargetException) {
@Suppress("DEPRECATION") // JDK11: isAccessible() should be replaced with canAccess() (since 9)
throw NotSerializableException( throw NotSerializableException(
"Setter ${setter.declaringClass}.${setter.name} (isAccessible=${setter.isAccessible} " + "Setter ${setter.declaringClass}.${setter.name} failed when called with parameter $value: ${e.cause?.message}"
"failed when called with parameter $value: ${e.cause!!.message}"
) )
} catch (e: IllegalAccessException) { } catch (e: IllegalAccessException) {
@Suppress("DEPRECATION") // JDK11: isAccessible() should be replaced with canAccess() (since 9) throw NotSerializableException("Setter ${setter.declaringClass}.${setter.name} not accessible: ${e.message}")
throw NotSerializableException(
"Setter ${setter.declaringClass}.${setter.name} (isAccessible=${setter.isAccessible} " +
"not accessible: ${e.message}"
)
} }
} }
} }
@ -206,7 +200,7 @@ private class SetterBasedObjectBuilder(
* and calling a constructor with those parameters to obtain the configured object instance. * and calling a constructor with those parameters to obtain the configured object instance.
*/ */
private class ConstructorBasedObjectBuilder( private class ConstructorBasedObjectBuilder(
private val constructorInfo: LocalConstructorInformation, constructorInfo: LocalConstructorInformation,
private val slotToCtorArgIdx: IntArray private val slotToCtorArgIdx: IntArray
) : ObjectBuilder { ) : ObjectBuilder {

View File

@ -5,24 +5,27 @@ import net.corda.core.identity.Party
import net.corda.core.internal.PLATFORM_VERSION import net.corda.core.internal.PLATFORM_VERSION
import net.corda.core.internal.concurrent.fork import net.corda.core.internal.concurrent.fork
import net.corda.core.internal.concurrent.transpose import net.corda.core.internal.concurrent.transpose
import net.corda.core.node.NodeInfo
import net.corda.core.node.NotaryInfo import net.corda.core.node.NotaryInfo
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.coretesting.internal.testThreadFactory
import net.corda.node.VersionInfo import net.corda.node.VersionInfo
import net.corda.node.internal.FlowManager import net.corda.node.internal.FlowManager
import net.corda.node.internal.Node import net.corda.node.internal.Node
import net.corda.node.internal.NodeFlowManager import net.corda.node.internal.NodeFlowManager
import net.corda.node.internal.NodeWithInfo import net.corda.node.internal.NodeWithInfo
import net.corda.node.services.config.* import net.corda.node.services.config.ConfigHelper
import net.corda.node.services.config.FlowOverrideConfig
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.configOf
import net.corda.node.services.config.parseAsNodeConfiguration
import net.corda.node.services.config.plus
import net.corda.nodeapi.internal.DevIdentityGenerator import net.corda.nodeapi.internal.DevIdentityGenerator
import net.corda.nodeapi.internal.config.toConfig import net.corda.nodeapi.internal.config.toConfig
import net.corda.nodeapi.internal.network.NetworkParametersCopier import net.corda.nodeapi.internal.network.NetworkParametersCopier
import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.driver.internal.incrementalPortAllocation import net.corda.testing.driver.internal.incrementalPortAllocation
import net.corda.coretesting.internal.testThreadFactory
import net.corda.testing.node.User import net.corda.testing.node.User
import org.apache.commons.lang3.SystemUtils
import org.apache.logging.log4j.Level import org.apache.logging.log4j.Level
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -34,7 +37,6 @@ import java.util.concurrent.Executors
import kotlin.concurrent.thread import kotlin.concurrent.thread
import kotlin.io.path.createDirectories import kotlin.io.path.createDirectories
import kotlin.io.path.div import kotlin.io.path.div
import kotlin.test.assertFalse
// TODO Some of the logic here duplicates what's in the driver - the reason why it's not straightforward to replace it by // TODO Some of the logic here duplicates what's in the driver - the reason why it's not straightforward to replace it by
// using DriverDSLImpl in `init()` and `stopAllNodes()` is because of the platform version passed to nodes (driver doesn't // using DriverDSLImpl in `init()` and `stopAllNodes()` is because of the platform version passed to nodes (driver doesn't
@ -161,12 +163,9 @@ class InProcessNode(
configuration: NodeConfiguration, configuration: NodeConfiguration,
versionInfo: VersionInfo, versionInfo: VersionInfo,
flowManager: FlowManager = NodeFlowManager(configuration.flowOverrides), flowManager: FlowManager = NodeFlowManager(configuration.flowOverrides),
allowHibernateToManageAppSchema: Boolean = true) : Node(configuration, versionInfo, false, flowManager = flowManager, allowHibernateToManageAppSchema = allowHibernateToManageAppSchema) { allowHibernateToManageAppSchema: Boolean = true
) : Node(configuration, versionInfo, false, flowManager = flowManager, allowHibernateToManageAppSchema = allowHibernateToManageAppSchema) {
override val runMigrationScripts: Boolean = true override val runMigrationScripts: Boolean = true
override fun start(): NodeInfo {
assertFalse(isInvalidJavaVersion(), "You are using a version of Java that is not supported (${SystemUtils.JAVA_VERSION}). Please upgrade to the latest version of Java 8.")
return super.start()
}
override val rxIoScheduler get() = CachedThreadScheduler(testThreadFactory()).also { runOnStop += it::shutdown } override val rxIoScheduler get() = CachedThreadScheduler(testThreadFactory()).also { runOnStop += it::shutdown }

View File

@ -54,8 +54,6 @@ fun main(args: Array<String>) {
val info = ManagementFactory.getRuntimeMXBean() val info = ManagementFactory.getRuntimeMXBean()
log.info("CommandLine Args: ${info.inputArguments.joinToString(" ")}") log.info("CommandLine Args: ${info.inputArguments.joinToString(" ")}")
log.info("Application Args: ${args.joinToString(" ")}") log.info("Application Args: ${args.joinToString(" ")}")
// JDK 11 (bootclasspath no longer supported from JDK 9)
if (info.isBootClassPathSupported) log.info("bootclasspath: ${info.bootClassPath}")
log.info("classpath: ${info.classPath}") log.info("classpath: ${info.classPath}")
log.info("VM ${info.vmName} ${info.vmVendor} ${info.vmVersion}") log.info("VM ${info.vmName} ${info.vmVendor} ${info.vmVersion}")
log.info("Machine: ${InetAddress.getLocalHost().hostName}") log.info("Machine: ${InetAddress.getLocalHost().hostName}")