Changed RMI object callback to only be "this", instead of passing the (internal) rmiID around. The RMI-ID is used for internal rmi messages, so that a request+response can be paired.

This commit is contained in:
Robinson 2021-04-27 13:30:42 +02:00
parent 09087b470a
commit ed76209925
8 changed files with 50 additions and 55 deletions

View File

@ -746,7 +746,7 @@ open class Client<CONNECTION : Connection>(config: Configuration = Configuration
*
* @see RemoteObject
*/
suspend inline fun <reified Iface> createObject(vararg objectParameters: Any?, noinline callback: suspend (Int, Iface) -> Unit) {
suspend inline fun <reified Iface> createObject(vararg objectParameters: Any?, noinline callback: suspend Iface.() -> Unit) {
// NOTE: It's not possible to have reified inside a virtual function
// https://stackoverflow.com/questions/60037849/kotlin-reified-generic-in-virtual-function
val kryoId = serialization.getKryoIdForRmiClient(Iface::class.java)
@ -776,7 +776,7 @@ open class Client<CONNECTION : Connection>(config: Configuration = Configuration
*
* @see RemoteObject
*/
suspend inline fun <reified Iface> createObject(noinline callback: suspend (Int, Iface) -> Unit) {
suspend inline fun <reified Iface> createObject(noinline callback: suspend Iface.() -> Unit) {
// NOTE: It's not possible to have reified inside a virtual function
// https://stackoverflow.com/questions/60037849/kotlin-reified-generic-in-virtual-function
val kryoId = serialization.getKryoIdForRmiClient(Iface::class.java)

View File

@ -648,8 +648,8 @@ open class Connection(connectionParameters: ConnectionParams<*>) {
*
* @see RemoteObject
*/
suspend fun <Iface> createObject(vararg objectParameters: Any?, callback: suspend (Int, Iface) -> Unit) {
val iFaceClass = ClassHelper.getGenericParameterAsClassForSuperClass(Function2::class.java, callback.javaClass, 1)
suspend fun <Iface> createObject(vararg objectParameters: Any?, callback: suspend Iface.() -> Unit) {
val iFaceClass = ClassHelper.getGenericParameterAsClassForSuperClass(Function1::class.java, callback.javaClass, 0)
val kryoId = endPoint.serialization.getKryoIdForRmiClient(iFaceClass)
@Suppress("UNCHECKED_CAST")
@ -675,8 +675,8 @@ open class Connection(connectionParameters: ConnectionParams<*>) {
*
* @see RemoteObject
*/
suspend fun <Iface> createObject(callback: suspend (Int, Iface) -> Unit) {
val iFaceClass = ClassHelper.getGenericParameterAsClassForSuperClass(Function2::class.java, callback.javaClass, 1)
suspend fun <Iface> createObject(callback: suspend Iface.() -> Unit) {
val iFaceClass = ClassHelper.getGenericParameterAsClassForSuperClass(Function1::class.java, callback.javaClass, 0)
val kryoId = endPoint.serialization.getKryoIdForRmiClient(iFaceClass)
rmiConnectionSupport.createRemoteObject(this, kryoId, null, callback)

View File

@ -74,7 +74,7 @@ internal class RmiManagerConnections<CONNECTION: Connection>(logger: KLogger,
/**
* on the "client" to create a connection-specific remote object (that exists on the server)
*/
suspend fun <Iface> createRemoteObject(connection: Connection, kryoId: Int, objectParameters: Array<Any?>?, callback: suspend (Int, Iface) -> Unit) {
suspend fun <Iface> createRemoteObject(connection: Connection, kryoId: Int, objectParameters: Array<Any?>?, callback: suspend Iface.() -> Unit) {
val callbackId = rmiGlobalSupport.registerCallback(callback)
// There is no rmiID yet, because we haven't created it!

View File

@ -18,12 +18,7 @@ package dorkbox.network.rmi
import dorkbox.network.connection.Connection
import dorkbox.network.connection.EndPoint
import dorkbox.network.connection.ListenerManager
import dorkbox.network.rmi.messages.ConnectionObjectCreateRequest
import dorkbox.network.rmi.messages.ConnectionObjectCreateResponse
import dorkbox.network.rmi.messages.GlobalObjectCreateRequest
import dorkbox.network.rmi.messages.GlobalObjectCreateResponse
import dorkbox.network.rmi.messages.MethodRequest
import dorkbox.network.rmi.messages.MethodResponse
import dorkbox.network.rmi.messages.*
import dorkbox.network.serialization.Serialization
import dorkbox.util.classes.ClassHelper
import kotlinx.coroutines.launch
@ -81,11 +76,11 @@ internal class RmiManagerGlobal<CONNECTION : Connection>(logger: KLogger,
private val remoteObjectCreationCallbacks = RemoteObjectStorage(logger)
internal fun <Iface> registerCallback(callback: suspend (Int, Iface) -> Unit): Int {
internal fun <Iface> registerCallback(callback: suspend Iface.() -> Unit): Int {
return remoteObjectCreationCallbacks.register(callback)
}
private fun removeCallback(callbackId: Int): suspend (Int, Any) -> Unit {
private fun removeCallback(callbackId: Int): suspend Any.() -> Unit {
// callback's area always correct, because we track them ourselves.
return remoteObjectCreationCallbacks.remove(callbackId)!!
}
@ -125,7 +120,7 @@ internal class RmiManagerGlobal<CONNECTION : Connection>(logger: KLogger,
connection: CONNECTION,
isGlobal: Boolean,
rmiId: Int,
callback: suspend (Int, Any) -> Unit,
callback: suspend Any.() -> Unit,
serialization: Serialization) {
// we only create the proxy + execute the callback if the RMI id is valid!
@ -134,7 +129,7 @@ internal class RmiManagerGlobal<CONNECTION : Connection>(logger: KLogger,
return
}
val interfaceClass = ClassHelper.getGenericParameterAsClassForSuperClass(RemoteObjectCallback::class.java, callback.javaClass, 1)
val interfaceClass = ClassHelper.getGenericParameterAsClassForSuperClass(RemoteObjectCallback::class.java, callback.javaClass, 0)
// 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)
@ -147,7 +142,7 @@ internal class RmiManagerGlobal<CONNECTION : Connection>(logger: KLogger,
// this should be executed on a NEW coroutine!
endPoint.actionDispatch.launch {
try {
callback(rmiId, proxyObject)
callback(proxyObject)
} catch (e: Exception) {
ListenerManager.cleanStackTrace(e)
endPoint.listenerManager.notifyError(e)

View File

@ -100,16 +100,16 @@ class SerializationValidationTest : BaseTest() {
client.onConnect { connection ->
connection.logger.error("Connected")
connection.createObject<TestObject> { rmiId, remoteObject ->
connection.createObject<TestObject> {
connection.logger.error("Starting test")
remoteObject.setValue(43.21f)
setValue(43.21f)
// Normal remote method call.
Assert.assertEquals(43.21f, remoteObject.other(), .0001f)
Assert.assertEquals(43.21f, other(), .0001f)
// When a proxy object is sent, the other side receives its ACTUAL object (not a proxy of it), because
// that is where that object actually exists.
connection.send(remoteObject)
connection.send(this)
}
}
@ -147,16 +147,16 @@ class SerializationValidationTest : BaseTest() {
client.onConnect { connection ->
connection.logger.error("Connected")
connection.createObject<TestObject> { rmiId, remoteObject ->
connection.createObject<TestObject> {
connection.logger.error("Starting test")
remoteObject.setValue(43.21f)
setValue(43.21f)
// Normal remote method call.
Assert.assertEquals(43.21f, remoteObject.other(), .0001f)
Assert.assertEquals(43.21f, other(), .0001f)
// When a proxy object is sent, the other side receives its ACTUAL object (not a proxy of it), because
// that is where that object actually exists.
connection.send(remoteObject)
connection.send(this)
}
}

View File

@ -90,17 +90,17 @@ class RmiNestedTest : BaseTest() {
client.onConnect { connection ->
connection.logger.error("Connected")
connection.createObject<TestObject> { rmiId, remoteObject ->
connection.createObject<TestObject> {
connection.logger.error("Starting test")
remoteObject.setValue(43.21f)
setValue(43.21f)
// Normal remote method call.
Assert.assertEquals(43.21f, remoteObject.other(), .0001f)
Assert.assertEquals(43.21f, other(), .0001f)
// Make a remote method call that returns another remote proxy object.
// the "test" object exists in the REMOTE side, as does the "OtherObject" that is created.
// here we have a proxy to both of them.
val otherObject: OtherObject = remoteObject.getOtherObject()
val otherObject: OtherObject = getOtherObject()
// Normal remote method call on the second object.
otherObject.setValue(12.34f)
@ -109,7 +109,7 @@ class RmiNestedTest : BaseTest() {
// make sure the "local" object and the "remote" object have the same values
Assert.assertEquals(12.34f, remoteObject.getOtherValue(), .0001f)
Assert.assertEquals(12.34f, getOtherValue(), .0001f)
// When a proxy object is sent, the other side receives its ACTUAL object (not a proxy of it), because
@ -157,17 +157,17 @@ class RmiNestedTest : BaseTest() {
client.onConnect { connection ->
connection.logger.error("Connected")
connection.createObject<TestObject> { rmiId, remoteObject ->
connection.createObject<TestObject> {
connection.logger.error("Starting test")
remoteObject.setValue(43.21f)
setValue(43.21f)
// Normal remote method call.
Assert.assertEquals(43.21f, remoteObject.other(), .0001f)
Assert.assertEquals(43.21f, other(), .0001f)
// Make a remote method call that returns another remote proxy object.
// the "test" object exists in the REMOTE side, as does the "OtherObject" that is created.
// here we have a proxy to both of them.
val otherObject: OtherObject = remoteObject.getOtherObject()
val otherObject: OtherObject = getOtherObject()
// Normal remote method call on the second object.
otherObject.setValue(12.34f)
@ -176,7 +176,7 @@ class RmiNestedTest : BaseTest() {
// make sure the "local" object and the "remote" object have the same values
Assert.assertEquals(12.34f, remoteObject.getOtherValue(), .0001f)
Assert.assertEquals(12.34f, getOtherValue(), .0001f)
// When a proxy object is sent, the other side receives its ACTUAL object (not a proxy of it), because
@ -224,15 +224,15 @@ class RmiNestedTest : BaseTest() {
client.onConnect { connection ->
connection.logger.error("Connected")
connection.createObject<TestObject> { rmiId, remoteObject ->
connection.createObject<TestObject> {
connection.logger.error("Starting test")
remoteObject.setOtherValue(43.21f)
setOtherValue(43.21f)
// Normal remote method call.
Assert.assertEquals(43.21f, remoteObject.getOtherValue(), .0001f)
Assert.assertEquals(43.21f, getOtherValue(), .0001f)
// real object
val otherObject: OtherObject = remoteObject.getOtherObject()
val otherObject: OtherObject = getOtherObject()
// Normal remote method call on the second object.
val value = otherObject.value()
@ -264,15 +264,15 @@ class RmiNestedTest : BaseTest() {
server.onConnect { connection ->
connection.logger.error("Connected")
connection.createObject<TestObject> { rmiId, remoteObject ->
connection.createObject<TestObject> {
connection.logger.error("Starting test")
remoteObject.setOtherValue(43.21f)
setOtherValue(43.21f)
// Normal remote method call.
Assert.assertEquals(43.21f, remoteObject.getOtherValue(), .0001f)
Assert.assertEquals(43.21f, getOtherValue(), .0001f)
// real object
val otherObject: OtherObject = remoteObject.getOtherObject()
val otherObject: OtherObject = getOtherObject()
// Normal remote method call on the second object.
val value = otherObject.value()

View File

@ -143,9 +143,9 @@ class RmiSimpleTest : BaseTest() {
server.logger.error("Starting test for: Server -> Client")
// NOTE: THIS IS BI-DIRECTIONAL!
connection.createObject<TestCow>(123) { rmiId, remoteObject ->
connection.createObject<TestCow>(123) {
server.logger.error("Running test for: Server -> Client")
RmiCommonTest.runTests(connection, remoteObject, 123)
RmiCommonTest.runTests(connection, this, 123)
server.logger.error("Done with test for: Server -> Client")
}
}
@ -160,9 +160,9 @@ class RmiSimpleTest : BaseTest() {
addEndPoint(client)
client.onConnect { connection ->
connection.createObject<TestCow>(23) { rmiId, remoteObject ->
connection.createObject<TestCow>(23) {
client.logger.error("Running test for: Client -> Server")
RmiCommonTest.runTests(connection, remoteObject, 23)
RmiCommonTest.runTests(connection, this, 23)
client.logger.error("Done with test for: Client -> Server")
}
}
@ -219,9 +219,9 @@ class RmiSimpleTest : BaseTest() {
server.logger.error("Finished test for: Client -> Server")
// normally this is in the 'connected', but we do it here, so that it's more linear and easier to debug
connection.createObject<TestCow>(4) { rmiId, remoteObject ->
connection.createObject<TestCow>(4) {
server.logger.error("Running test for: Server -> Client")
RmiCommonTest.runTests(connection, remoteObject, 4)
RmiCommonTest.runTests(connection, this, 4)
server.logger.error("Done with test for: Server -> Client")
}
}
@ -256,9 +256,9 @@ class RmiSimpleTest : BaseTest() {
client.logger.error("Starting test for: Client -> Server")
// this creates a GLOBAL object on the server (instead of a connection specific object)
client.createObject<TestCow>(44) { rmiId, remoteObject ->
client.createObject<TestCow>(44) {
client.logger.error("Running test for: Client -> Server")
RmiCommonTest.runTests(client.connection, remoteObject, 44)
RmiCommonTest.runTests(client.connection, this, 44)
client.logger.error("Done with test for: Client -> Server")
}
}

View File

@ -78,12 +78,12 @@ object TestClient {
client.onConnect { connection ->
connection.logger.error("Starting test for: Client -> Server")
connection.createObject<TestCow>(124123) { _, remoteObject ->
RmiCommonTest.runTests(connection, remoteObject, 124123)
connection.createObject<TestCow>(124123) {
RmiCommonTest.runTests(connection, this, 124123)
connection.logger.error("DONE")
// now send this remote object ACROSS the wire to the server (on the server, this is where the IMPLEMENTATION lives)
connection.send(remoteObject)
connection.send(this)
client.close()
}