Fixed issues with reverse RMI and having the client register impl classes (instead of the server)
This commit is contained in:
parent
b5342cd2f8
commit
b1e92be50b
@ -63,7 +63,7 @@ internal abstract class ClassRegistration(val clazz: Class<*>, val serializer: S
|
|||||||
// otherwise, we are OK to continue to register this
|
// otherwise, we are OK to continue to register this
|
||||||
register(kryo)
|
register(kryo)
|
||||||
|
|
||||||
if (serializer != null && overriddenSerializer != serializer) {
|
if (serializer != null && overriddenSerializer != null && overriddenSerializer != serializer) {
|
||||||
info = "$info (Replaced $overriddenSerializer)"
|
info = "$info (Replaced $overriddenSerializer)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ import dorkbox.network.rmi.messages.RmiServerSerializer
|
|||||||
* If the impl object 'lives' on the SERVER, then the server must tell the client about the iface ID
|
* If the impl object 'lives' on the SERVER, then the server must tell the client about the iface ID
|
||||||
*/
|
*/
|
||||||
internal class ClassRegistrationForRmi(ifaceClass: Class<*>,
|
internal class ClassRegistrationForRmi(ifaceClass: Class<*>,
|
||||||
val implClass: Class<*>?,
|
var implClass: Class<*>?,
|
||||||
serializer: RmiServerSerializer) : ClassRegistration(ifaceClass, serializer) {
|
serializer: RmiServerSerializer) : ClassRegistration(ifaceClass, serializer) {
|
||||||
/**
|
/**
|
||||||
* In general:
|
* In general:
|
||||||
@ -106,21 +106,55 @@ internal class ClassRegistrationForRmi(ifaceClass: Class<*>,
|
|||||||
override fun register(kryo: KryoExtra, rmi: RmiHolder) {
|
override fun register(kryo: KryoExtra, rmi: RmiHolder) {
|
||||||
// we override this, because we ALWAYS will call our RMI registration!
|
// we override this, because we ALWAYS will call our RMI registration!
|
||||||
|
|
||||||
// have to get the ID for the interface (if it exists)
|
if (implClass == null) {
|
||||||
val registration = kryo.classResolver.getRegistration(clazz) // this is ifaceClass, and must match what is defined on the rmi client
|
// this means we are the RMI-CLIENT
|
||||||
|
|
||||||
|
// see if we have the IMPL registered? NOT LIKELY, but possible
|
||||||
|
val existingId = rmi.ifaceToId[clazz]
|
||||||
|
if (existingId != null) {
|
||||||
|
implClass = rmi.idToImpl[existingId]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (implClass == null) {
|
||||||
|
// then we just register the interface class!
|
||||||
|
|
||||||
|
val registration = kryo.classResolver.getRegistration(clazz)
|
||||||
|
if (registration != null) {
|
||||||
|
id = registration.id
|
||||||
|
|
||||||
|
// override that registration
|
||||||
|
kryo.register(clazz, serializer, id)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// just register the iface class
|
||||||
|
id = kryo.register(clazz, serializer).id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (implClass != null) {
|
||||||
|
// this means we are the RMI-SERVER
|
||||||
|
val registration = kryo.classResolver.getRegistration(implClass) // we cannot register iface classes!
|
||||||
if (registration != null) {
|
if (registration != null) {
|
||||||
id = registration.id
|
id = registration.id
|
||||||
|
|
||||||
// override that registration
|
// override that registration
|
||||||
kryo.register(implClass, serializer, id)
|
kryo.register(implClass, serializer, id)
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// now register the impl class
|
// now register the impl class
|
||||||
id = kryo.register(implClass, serializer).id
|
id = kryo.register(implClass, serializer).id
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// have to get the ID for the interface (if it exists)
|
||||||
info = if (implClass == null) {
|
info = if (implClass == null) {
|
||||||
"Registered $id -> (RMI-CLIENT) ${clazz.name}"
|
"Registered $id -> (RMI-CLIENT) ${clazz.name}"
|
||||||
} else {
|
} else {
|
||||||
"Registered $id -> (RMI-SERVER) ${clazz.name} -> ${implClass.name}"
|
"Registered $id -> (RMI-SERVER) ${clazz.name} -> ${implClass!!.name}"
|
||||||
}
|
}
|
||||||
|
|
||||||
// now, we want to save the relationship between classes and kryoId
|
// now, we want to save the relationship between classes and kryoId
|
||||||
@ -128,16 +162,18 @@ internal class ClassRegistrationForRmi(ifaceClass: Class<*>,
|
|||||||
rmi.idToIface[id] = clazz
|
rmi.idToIface[id] = clazz
|
||||||
|
|
||||||
// we have to know what the IMPL class is so we can create it for a "createObject" RMI command
|
// we have to know what the IMPL class is so we can create it for a "createObject" RMI command
|
||||||
|
if (implClass != null) {
|
||||||
rmi.implToId[implClass] = id
|
rmi.implToId[implClass] = id
|
||||||
rmi.idToImpl[id] = implClass
|
rmi.idToImpl[id] = implClass
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun getInfoArray(): Array<Any> {
|
override fun getInfoArray(): Array<Any> {
|
||||||
// the info array has to match for the INTERFACE (not the impl!)
|
// the info array has to match for the INTERFACE (not the impl!)
|
||||||
return if (implClass == null) {
|
return if (implClass == null) {
|
||||||
arrayOf(4, id, clazz.name, serializer!!::class.java.name, "")
|
arrayOf(4, id, clazz.name, serializer!!::class.java.name, "")
|
||||||
} else {
|
} else {
|
||||||
arrayOf(4, id, clazz.name, serializer!!::class.java.name, implClass.name)
|
arrayOf(4, id, clazz.name, serializer!!::class.java.name, implClass!!.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,14 +228,22 @@ open class Serialization(private val references: Boolean = true, private val fac
|
|||||||
*
|
*
|
||||||
* This is NOT bi-directional, and this endpoint cannot access or create remote objects on the "remote client".
|
* This is NOT bi-directional, and this endpoint cannot access or create remote objects on the "remote client".
|
||||||
*
|
*
|
||||||
|
* @param ifaceClass this must be the interface class used for RMI
|
||||||
|
* @param implClass this must be the implementation class used for RMI
|
||||||
|
* If *null* it means that this endpoint is the rmi-client
|
||||||
|
* If *not-null* it means that this endpoint is the rmi-server
|
||||||
|
*
|
||||||
* @throws IllegalArgumentException if the iface/impl have previously been overridden
|
* @throws IllegalArgumentException if the iface/impl have previously been overridden
|
||||||
*/
|
*/
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun <Iface, Impl : Iface> registerRmi(ifaceClass: Class<Iface>, implClass: Class<Impl>): Serialization {
|
fun <Iface, Impl : Iface> registerRmi(ifaceClass: Class<Iface>, implClass: Class<Impl>? = null): Serialization {
|
||||||
require(!initialized.value) { "Serialization 'registerRmi(Class, Class)' cannot happen after client/server initialization!" }
|
require(!initialized.value) { "Serialization 'registerRmi(Class, Class)' cannot happen after client/server initialization!" }
|
||||||
|
|
||||||
require(ifaceClass.isInterface) { "Cannot register an implementation for RMI access. It must be an interface." }
|
require(ifaceClass.isInterface) { "Cannot register an implementation for RMI access. It must be an interface." }
|
||||||
|
|
||||||
|
if (implClass != null) {
|
||||||
require(!implClass.isInterface) { "Cannot register an interface for RMI implementations. It must be an implementation." }
|
require(!implClass.isInterface) { "Cannot register an interface for RMI implementations. It must be an implementation." }
|
||||||
|
}
|
||||||
|
|
||||||
classesToRegister.add(ClassRegistrationForRmi(ifaceClass, implClass, rmiServerSerializer))
|
classesToRegister.add(ClassRegistrationForRmi(ifaceClass, implClass, rmiServerSerializer))
|
||||||
return this
|
return this
|
||||||
@ -332,7 +340,6 @@ open class Serialization(private val references: Boolean = true, private val fac
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
require(classesToRegister.isEmpty()) { "Unable to initialize a non-empty class registration state! Make sure there are no serialization registrations for the client!" }
|
|
||||||
initializeClient(kryoRegistrationDetailsFromServer)
|
initializeClient(kryoRegistrationDetailsFromServer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -459,7 +466,18 @@ open class Serialization(private val references: Boolean = true, private val fac
|
|||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
private fun initializeClient(kryoRegistrationDetailsFromServer: ByteArray): Boolean {
|
private fun initializeClient(kryoRegistrationDetailsFromServer: ByteArray): Boolean {
|
||||||
val kryo = initKryo()
|
// we have to allow CUSTOM classes to register (where the order does not matter), so that if the CLIENT is the RMI-SERVER, it can
|
||||||
|
// specify IMPL classes for RMI.
|
||||||
|
classesToRegister.forEach { registration ->
|
||||||
|
require(registration is ClassRegistrationForRmi) { "Unable to initialize a class registrations for anything OTHER than RMI!! To fix this, remove ${registration.clazz}" }
|
||||||
|
}
|
||||||
|
val classesToRegisterForRmi = listOf(*classesToRegister.toTypedArray()) as List<ClassRegistrationForRmi>
|
||||||
|
classesToRegister.clear()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var kryo = initKryo()
|
||||||
val input = AeronInput(kryoRegistrationDetailsFromServer)
|
val input = AeronInput(kryoRegistrationDetailsFromServer)
|
||||||
val clientClassRegistrations = kryo.readCompressed(logger, input, kryoRegistrationDetailsFromServer.size) as Array<Array<Any>>
|
val clientClassRegistrations = kryo.readCompressed(logger, input, kryoRegistrationDetailsFromServer.size) as Array<Array<Any>>
|
||||||
|
|
||||||
@ -486,16 +504,18 @@ open class Serialization(private val references: Boolean = true, private val fac
|
|||||||
// we literally want everything to be 100% the same.
|
// we literally want everything to be 100% the same.
|
||||||
// the only WEIRD case is when the client == rmi-server (in which case, the IMPL object is on the client)
|
// the only WEIRD case is when the client == rmi-server (in which case, the IMPL object is on the client)
|
||||||
// for this, the server (rmi-client) WILL ALSO have the same registration info. (bi-directional RMI, but not really)
|
// for this, the server (rmi-client) WILL ALSO have the same registration info. (bi-directional RMI, but not really)
|
||||||
val implClazzName = bytes[4] as String
|
val implClassName = bytes[4] as String
|
||||||
var implClass: Class<*>? = null
|
var implClass: Class<*>? = classesToRegisterForRmi.firstOrNull { it.clazz.name == clazzName }?.implClass
|
||||||
|
|
||||||
if (implClazzName.isNotEmpty()) {
|
// if we do not have the impl class specified by the registrations for RMI, then do a lookup to see if we have access to it as the client
|
||||||
|
if (implClass == null) {
|
||||||
try {
|
try {
|
||||||
implClass = Class.forName(implClazzName)
|
implClass = Class.forName(implClassName)
|
||||||
} catch (ignored: Exception) {
|
} catch (ignored: Exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// implClass MIGHT BE NULL!
|
||||||
classesToRegister.add(ClassRegistrationForRmi(clazz, implClass, rmiServerSerializer))
|
classesToRegister.add(ClassRegistrationForRmi(clazz, implClass, rmiServerSerializer))
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -512,11 +532,8 @@ open class Serialization(private val references: Boolean = true, private val fac
|
|||||||
// we have to re-init so the registrations are set!
|
// we have to re-init so the registrations are set!
|
||||||
initKryo()
|
initKryo()
|
||||||
|
|
||||||
// now do a round-trip through the server serialization to make sure our byte arrays are THE SAME.
|
// now do a round-trip through the class registrations
|
||||||
initializeClassRegistrations()
|
return initializeClassRegistrations()
|
||||||
|
|
||||||
// verify the registration ID data is THE SAME!
|
|
||||||
return savedRegistrationDetails.contentEquals(kryoRegistrationDetailsFromServer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user