mirror of
https://github.com/corda/corda.git
synced 2025-06-17 22:58:19 +00:00
[CORDA-2431] - Small refactorings following-up on PR-4551 (#4564)
* Small refactorings following-up on PR-4551 * Adjust thread context class loader * Address Shams' comments
This commit is contained in:
@ -40,6 +40,7 @@ import net.corda.node.internal.cordapp.*
|
||||
import net.corda.node.internal.rpc.proxies.AuthenticatedRpcOpsProxy
|
||||
import net.corda.node.internal.rpc.proxies.ExceptionMaskingRpcOpsProxy
|
||||
import net.corda.node.internal.rpc.proxies.ExceptionSerialisingRpcOpsProxy
|
||||
import net.corda.node.internal.rpc.proxies.ThreadContextAdjustingRpcOpsProxy
|
||||
import net.corda.node.services.ContractUpgradeHandler
|
||||
import net.corda.node.services.FinalityHandler
|
||||
import net.corda.node.services.NotaryChangeHandler
|
||||
@ -254,7 +255,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
}
|
||||
|
||||
/** The implementation of the [CordaRPCOps] interface used by this node. */
|
||||
open fun makeRPCOps(): CordaRPCOps {
|
||||
open fun makeRPCOps(cordappLoader: CordappLoader): CordaRPCOps {
|
||||
val ops: CordaRPCOps = CordaRPCOpsImpl(services, smm, flowStarter) { shutdownExecutor.submit { stop() } }.also { it.closeOnStop() }
|
||||
val proxies = mutableListOf<(CordaRPCOps) -> CordaRPCOps>()
|
||||
// Mind that order is relevant here.
|
||||
@ -263,6 +264,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
proxies += { it -> ExceptionMaskingRpcOpsProxy(it, true) }
|
||||
}
|
||||
proxies += { it -> ExceptionSerialisingRpcOpsProxy(it, configuration.devMode) }
|
||||
proxies += { it -> ThreadContextAdjustingRpcOpsProxy(it, cordappLoader.appClassLoader) }
|
||||
return proxies.fold(ops) { delegate, decorate -> decorate(delegate) }
|
||||
}
|
||||
|
||||
@ -323,7 +325,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
installCoreFlows()
|
||||
registerCordappFlows()
|
||||
services.rpcFlows += cordappLoader.cordapps.flatMap { it.rpcFlows }
|
||||
val rpcOps = makeRPCOps()
|
||||
val rpcOps = makeRPCOps(cordappLoader)
|
||||
startShell()
|
||||
networkMapClient?.start(trustRoot)
|
||||
|
||||
|
@ -0,0 +1,29 @@
|
||||
package net.corda.node.internal.rpc.proxies
|
||||
|
||||
import net.corda.core.internal.executeWithThreadContextClassLoader
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.node.internal.InvocationHandlerTemplate
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Proxy
|
||||
|
||||
/**
|
||||
* A [CordaRPCOps] proxy that adjusts the thread context's class loader temporarily on every invocation with the provided classloader.
|
||||
* As an example, this can be used to work-around cases, where 3rd party libraries prioritise the thread context's class loader over the current one,
|
||||
* without sensible fallbacks to the classloader of the current instance.
|
||||
* If clients' CorDapps use one of these libraries, this temporary adjustment can ensure that any provided classes from these libraries will be available during RPC calls.
|
||||
*/
|
||||
internal class ThreadContextAdjustingRpcOpsProxy(private val delegate: CordaRPCOps, private val classLoader: ClassLoader): CordaRPCOps by proxy(delegate, classLoader) {
|
||||
private companion object {
|
||||
private fun proxy(delegate: CordaRPCOps, classLoader: ClassLoader): CordaRPCOps {
|
||||
val handler = ThreadContextAdjustingRpcOpsProxy.ThreadContextAdjustingInvocationHandler(delegate, classLoader)
|
||||
return Proxy.newProxyInstance(delegate::class.java.classLoader, arrayOf(CordaRPCOps::class.java), handler) as CordaRPCOps
|
||||
}
|
||||
}
|
||||
|
||||
private class ThreadContextAdjustingInvocationHandler(override val delegate: CordaRPCOps, private val classLoader: ClassLoader) : InvocationHandlerTemplate {
|
||||
override fun invoke(proxy: Any, method: Method, arguments: Array<out Any?>?): Any? {
|
||||
return executeWithThreadContextClassLoader(this.classLoader) { super.invoke(proxy, method, arguments) }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package net.corda.node.internal.rpc.proxies
|
||||
|
||||
import com.nhaarman.mockito_kotlin.any
|
||||
import com.nhaarman.mockito_kotlin.mock
|
||||
import net.corda.core.flows.StateMachineRunId
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
import org.mockito.Mockito.`when`
|
||||
|
||||
class ThreadContextAdjustingRpcOpsProxyTest {
|
||||
|
||||
private val coreOps = mock<InstrumentedCordaRPCOps>()
|
||||
private val mockClassloader = mock<ClassLoader>()
|
||||
private val proxy = ThreadContextAdjustingRpcOpsProxy(coreOps, mockClassloader)
|
||||
|
||||
|
||||
private interface InstrumentedCordaRPCOps: CordaRPCOps {
|
||||
fun getThreadContextClassLoader(): ClassLoader = Thread.currentThread().contextClassLoader
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyThreadContextIsAdjustedTemporarily() {
|
||||
`when`(coreOps.killFlow(any())).thenAnswer {
|
||||
assertThat(Thread.currentThread().contextClassLoader).isEqualTo(mockClassloader)
|
||||
true
|
||||
}
|
||||
|
||||
val result = proxy.killFlow(StateMachineRunId.createRandom())
|
||||
assertThat(Thread.currentThread().contextClassLoader).isNotEqualTo(mockClassloader)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user