From c117c90ee5df9a22f55ae176c277bff1a68068d0 Mon Sep 17 00:00:00 2001 From: nathan Date: Thu, 20 Aug 2020 23:28:12 +0200 Subject: [PATCH] RMI proxy objects no longer save "globally", but instead now are saved per connection --- src/dorkbox/network/Client.kt | 6 +- src/dorkbox/network/connection/EndPoint.kt | 10 +-- src/dorkbox/network/rmi/RmiClient.kt | 2 +- ...onnections.kt => RmiManagerConnections.kt} | 35 ++++++-- ...iMessageManager.kt => RmiManagerGlobal.kt} | 87 ++++++++++--------- src/dorkbox/network/rmi/RmiObjectCache.kt | 18 ---- 6 files changed, 83 insertions(+), 75 deletions(-) rename src/dorkbox/network/rmi/{RmiManagerForConnections.kt => RmiManagerConnections.kt} (80%) rename src/dorkbox/network/rmi/{RmiMessageManager.kt => RmiManagerGlobal.kt} (89%) diff --git a/src/dorkbox/network/Client.kt b/src/dorkbox/network/Client.kt index 074873cd..99209375 100644 --- a/src/dorkbox/network/Client.kt +++ b/src/dorkbox/network/Client.kt @@ -30,7 +30,7 @@ import dorkbox.network.connection.UdpMediaDriverConnection import dorkbox.network.handshake.ClientHandshake import dorkbox.network.rmi.RemoteObject import dorkbox.network.rmi.RemoteObjectStorage -import dorkbox.network.rmi.RmiManagerForConnections +import dorkbox.network.rmi.RmiManagerConnections import dorkbox.network.rmi.TimeoutException import dorkbox.util.exceptions.SecurityException import kotlinx.coroutines.launch @@ -72,7 +72,7 @@ open class Client(config: Configuration = Configuration private val previousClosedConnectionActivity: Long = 0 private val handshake = ClientHandshake(logger, config, crypto, listenerManager) - private val rmiConnectionSupport = RmiManagerForConnections(logger, rmiGlobalSupport, serialization, actionDispatch) + private val rmiConnectionSupport = RmiManagerConnections(logger, rmiGlobalSupport, serialization, actionDispatch) init { // have to do some basic validation of our configuration @@ -93,7 +93,7 @@ open class Client(config: Configuration = Configuration /** * So the client class can get remote objects that are THE SAME OBJECT as if called from a connection */ - override fun getRmiConnectionSupport(): RmiManagerForConnections { + override fun getRmiConnectionSupport(): RmiManagerConnections { return rmiConnectionSupport } diff --git a/src/dorkbox/network/connection/EndPoint.kt b/src/dorkbox/network/connection/EndPoint.kt index 437d76d5..dec55f14 100644 --- a/src/dorkbox/network/connection/EndPoint.kt +++ b/src/dorkbox/network/connection/EndPoint.kt @@ -22,8 +22,8 @@ import dorkbox.network.ServerConfiguration import dorkbox.network.aeron.CoroutineIdleStrategy import dorkbox.network.connection.ping.PingMessage import dorkbox.network.ipFilter.IpFilterRule -import dorkbox.network.rmi.RmiManagerForConnections -import dorkbox.network.rmi.RmiMessageManager +import dorkbox.network.rmi.RmiManagerConnections +import dorkbox.network.rmi.RmiManagerGlobal import dorkbox.network.rmi.messages.RmiMessage import dorkbox.network.serialization.KryoExtra import dorkbox.network.serialization.NetworkSerializationManager @@ -133,7 +133,7 @@ internal constructor(val type: Class<*>, internal val config: Configuration) : A // we only want one instance of these created. These will be called appropriately val settingsStore: SettingsStore - internal val rmiGlobalSupport = RmiMessageManager(logger, actionDispatch, config.serialization) + internal val rmiGlobalSupport = RmiManagerGlobal(logger, actionDispatch, config.serialization) init { logger.error("NETWORK STACK IS ONLY IPV4 AT THE MOMENT. IPV6 is in progress!") @@ -318,8 +318,8 @@ internal constructor(val type: Class<*>, internal val config: Configuration) : A * Used for the client, because the client only has ONE ever support connection, and it allows us to create connection specific objects * from a "global" context */ - internal open fun getRmiConnectionSupport() : RmiManagerForConnections { - return RmiManagerForConnections(logger, rmiGlobalSupport, serialization, actionDispatch) + internal open fun getRmiConnectionSupport() : RmiManagerConnections { + return RmiManagerConnections(logger, rmiGlobalSupport, serialization, actionDispatch) } /** diff --git a/src/dorkbox/network/rmi/RmiClient.kt b/src/dorkbox/network/rmi/RmiClient.kt index dc2b410d..ed674c26 100644 --- a/src/dorkbox/network/rmi/RmiClient.kt +++ b/src/dorkbox/network/rmi/RmiClient.kt @@ -124,7 +124,7 @@ internal class RmiClient(val isGlobal: Boolean, // manage all of the RemoteObject proxy methods when (method) { closeMethod -> { - rmiObjectCache.removeProxyObject(rmiObjectId) + connection.rmiConnectionSupport.removeProxyObject(rmiObjectId) return null } diff --git a/src/dorkbox/network/rmi/RmiManagerForConnections.kt b/src/dorkbox/network/rmi/RmiManagerConnections.kt similarity index 80% rename from src/dorkbox/network/rmi/RmiManagerForConnections.kt rename to src/dorkbox/network/rmi/RmiManagerConnections.kt index f523faff..be5c1012 100644 --- a/src/dorkbox/network/rmi/RmiManagerForConnections.kt +++ b/src/dorkbox/network/rmi/RmiManagerConnections.kt @@ -20,13 +20,31 @@ import dorkbox.network.connection.EndPoint import dorkbox.network.rmi.messages.ConnectionObjectCreateRequest import dorkbox.network.rmi.messages.ConnectionObjectCreateResponse import dorkbox.network.serialization.NetworkSerializationManager +import dorkbox.util.collections.LockFreeIntMap import kotlinx.coroutines.CoroutineScope import mu.KLogger -internal class RmiManagerForConnections(logger: KLogger, - val rmiGlobalSupport: RmiMessageManager, - private val serialization: NetworkSerializationManager, - actionDispatch: CoroutineScope) : RmiObjectCache(logger, actionDispatch) { +internal class RmiManagerConnections(logger: KLogger, + val rmiGlobalSupport: RmiManagerGlobal, + private val serialization: NetworkSerializationManager, + actionDispatch: CoroutineScope) : RmiObjectCache(logger, actionDispatch) { + + private val proxyObjects = LockFreeIntMap() + + /** + * Removes a proxy object from the system + */ + fun removeProxyObject(rmiId: Int) { + proxyObjects.remove(rmiId) + } + + fun getProxyObject(rmiId: Int): RemoteObject? { + return proxyObjects[rmiId] + } + + fun saveProxyObject(rmiId: Int, remoteObject: RemoteObject) { + proxyObjects.put(rmiId, remoteObject) + } private fun createProxyObject(isGlobalObject: Boolean, connection: Connection, @@ -37,7 +55,7 @@ internal class RmiManagerForConnections(logger: KLogger, // so we can just instantly create the proxy object (or get the cached one) var proxyObject = getProxyObject(objectId) if (proxyObject == null) { - proxyObject = RmiMessageManager.createProxyObject(isGlobalObject, connection, serialization, rmiGlobalSupport, endPoint.type.simpleName, objectId, interfaceClass) + proxyObject = RmiManagerGlobal.createProxyObject(isGlobalObject, connection, serialization, rmiGlobalSupport, endPoint.type.simpleName, objectId, interfaceClass) saveProxyObject(objectId, proxyObject) } @@ -95,7 +113,7 @@ internal class RmiManagerForConnections(logger: KLogger, // this means we could register this object. // next, scan this object to see if there are any RMI fields - RmiMessageManager.scanImplForRmiFields(logger, implObject) { + RmiManagerGlobal.scanImplForRmiFields(logger, implObject) { saveImplObject(it) } } else { @@ -110,4 +128,9 @@ internal class RmiManagerForConnections(logger: KLogger, connection.send(response) } + + override fun close() { + proxyObjects.clear() + super.close() + } } diff --git a/src/dorkbox/network/rmi/RmiMessageManager.kt b/src/dorkbox/network/rmi/RmiManagerGlobal.kt similarity index 89% rename from src/dorkbox/network/rmi/RmiMessageManager.kt rename to src/dorkbox/network/rmi/RmiManagerGlobal.kt index 1df2f22f..a7814374 100644 --- a/src/dorkbox/network/rmi/RmiMessageManager.kt +++ b/src/dorkbox/network/rmi/RmiManagerGlobal.kt @@ -26,17 +26,17 @@ import dorkbox.network.rmi.messages.MethodRequest import dorkbox.network.rmi.messages.MethodResponse import dorkbox.network.serialization.NetworkSerializationManager import dorkbox.util.classes.ClassHelper +import dorkbox.util.collections.LockFreeIntMap import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import mu.KLogger import java.lang.reflect.Proxy import java.util.* -internal class RmiMessageManager(logger: KLogger, - actionDispatch: CoroutineScope, - internal val serialization: NetworkSerializationManager) : RmiObjectCache(logger, actionDispatch) { +internal class RmiManagerGlobal(logger: KLogger, + actionDispatch: CoroutineScope, + internal val serialization: NetworkSerializationManager) : RmiObjectCache(logger, actionDispatch) { companion object { - /** * Returns a proxy object that implements the specified interface, and the methods invoked on the proxy object will be invoked * remotely. @@ -74,7 +74,7 @@ internal class RmiMessageManager(logger: KLogger, // This is the interface inheritance by the proxy object val interfaces: Array> = arrayOf(RemoteObject::class.java, interfaceClass) - return Proxy.newProxyInstance(RmiMessageManager::class.java.classLoader, interfaces, proxyObject) as RemoteObject + return Proxy.newProxyInstance(RmiManagerGlobal::class.java.classLoader, interfaces, proxyObject) as RemoteObject } /** @@ -129,42 +129,10 @@ internal class RmiMessageManager(logger: KLogger, } } } - - /** - * called on "client" - */ - private fun onGenericObjectResponse(endPoint: EndPoint<*>, connection: Connection, logger: KLogger, - isGlobal: Boolean, rmiId: Int, callback: suspend (Int, Any) -> Unit, - rmiObjectCache: RmiObjectCache, serialization: NetworkSerializationManager) { - - // we only create the proxy + execute the callback if the RMI id is valid! - if (rmiId == RemoteObjectStorage.INVALID_RMI) { - logger.error { - "RMI ID '${rmiId}' is invalid. Unable to create RMI object on server." - } - return - } - - val interfaceClass = ClassHelper.getGenericParameterAsClassForSuperClass(RemoteObjectCallback::class.java, callback.javaClass, 1) - - // create the client-side proxy object, if possible - var proxyObject = rmiObjectCache.getProxyObject(rmiId) - if (proxyObject == null) { - proxyObject = createProxyObject(isGlobal, connection, serialization, rmiObjectCache, endPoint.type.simpleName, rmiId, interfaceClass) - rmiObjectCache.saveProxyObject(rmiId, proxyObject) - } - - // this should be executed on a NEW coroutine! - endPoint.actionDispatch.launch { - try { - callback(rmiId, proxyObject) - } catch (e: Exception) { - logger.error("Error getting or creating the remote object $interfaceClass", e) - } - } - } } + private val proxyObjects = LockFreeIntMap() + // this is used for all connection specific ones as well. private val remoteObjectCreationCallbacks = RemoteObjectStorage(logger) @@ -243,17 +211,52 @@ internal class RmiMessageManager(logger: KLogger, remoteObjectCreationCallbacks.close() } + + /** + * called on "client" + */ + private fun onGenericObjectResponse(endPoint: EndPoint<*>, connection: Connection, logger: KLogger, + isGlobal: Boolean, rmiId: Int, callback: suspend (Int, Any) -> Unit, + rmiObjectCache: RmiObjectCache, serialization: NetworkSerializationManager) { + + // we only create the proxy + execute the callback if the RMI id is valid! + if (rmiId == RemoteObjectStorage.INVALID_RMI) { + logger.error { + "RMI ID '${rmiId}' is invalid. Unable to create RMI object on server." + } + return + } + + val interfaceClass = ClassHelper.getGenericParameterAsClassForSuperClass(RemoteObjectCallback::class.java, callback.javaClass, 1) + + // create the client-side proxy object, if possible. This MUST be an object that is saved for the connection + var proxyObject = connection.rmiConnectionSupport.getProxyObject(rmiId) + if (proxyObject == null) { + proxyObject = createProxyObject(isGlobal, connection, serialization, rmiObjectCache, endPoint.type.simpleName, rmiId, interfaceClass) + connection.rmiConnectionSupport.saveProxyObject(rmiId, proxyObject) + } + + // this should be executed on a NEW coroutine! + endPoint.actionDispatch.launch { + try { + callback(rmiId, proxyObject) + } catch (e: Exception) { + logger.error("Error getting or creating the remote object $interfaceClass", e) + } + } + } + /** * on the connection+client to get a global remote object (that exists on the server) */ fun getGlobalRemoteObject(connection: Connection, endPoint: EndPoint<*>, objectId: Int, interfaceClass: Class): Iface { // this immediately returns BECAUSE the object must have already been created on the server (this is why we specify the rmiId)! - // so we can just instantly create the proxy object (or get the cached one) - var proxyObject = getProxyObject(objectId) + // so we can just instantly create the proxy object (or get the cached one). This MUST be an object that is saved for the connection + var proxyObject = connection.rmiConnectionSupport.getProxyObject(objectId) if (proxyObject == null) { proxyObject = createProxyObject(true, connection, serialization, this, endPoint.type.simpleName, objectId, interfaceClass) - saveProxyObject(objectId, proxyObject) + connection.rmiConnectionSupport.saveProxyObject(objectId, proxyObject) } @Suppress("UNCHECKED_CAST") diff --git a/src/dorkbox/network/rmi/RmiObjectCache.kt b/src/dorkbox/network/rmi/RmiObjectCache.kt index da6af1ae..a50cb9fb 100644 --- a/src/dorkbox/network/rmi/RmiObjectCache.kt +++ b/src/dorkbox/network/rmi/RmiObjectCache.kt @@ -15,7 +15,6 @@ */ package dorkbox.network.rmi -import dorkbox.util.collections.LockFreeIntMap import kotlinx.coroutines.CoroutineScope import mu.KLogger @@ -29,7 +28,6 @@ internal open class RmiObjectCache(logger: KLogger, actionDispatch: CoroutineSco private val responseStorage = RmiResponseManager(logger, actionDispatch) private val implObjects = RemoteObjectStorage(logger) - private val proxyObjects = LockFreeIntMap() fun saveImplObject(rmiObject: Any): Int { return implObjects.register(rmiObject) @@ -48,21 +46,6 @@ internal open class RmiObjectCache(logger: KLogger, actionDispatch: CoroutineSco return implObjects.remove(rmiId) as T? } - /** - * Removes a proxy object from the system - */ - fun removeProxyObject(rmiId: Int) { - proxyObjects.remove(rmiId) - } - - fun getProxyObject(rmiId: Int): RemoteObject? { - return proxyObjects[rmiId] - } - - fun saveProxyObject(rmiId: Int, remoteObject: RemoteObject) { - proxyObjects.put(rmiId, remoteObject) - } - fun getResponseStorage(): RmiResponseManager { return responseStorage } @@ -70,6 +53,5 @@ internal open class RmiObjectCache(logger: KLogger, actionDispatch: CoroutineSco open fun close() { responseStorage.close() implObjects.close() - proxyObjects.clear() } }