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
|
||||
register(kryo)
|
||||
|
||||
if (serializer != null && overriddenSerializer != serializer) {
|
||||
if (serializer != null && overriddenSerializer != null && overriddenSerializer != serializer) {
|
||||
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
|
||||
*/
|
||||
internal class ClassRegistrationForRmi(ifaceClass: Class<*>,
|
||||
val implClass: Class<*>?,
|
||||
var implClass: Class<*>?,
|
||||
serializer: RmiServerSerializer) : ClassRegistration(ifaceClass, serializer) {
|
||||
/**
|
||||
* In general:
|
||||
@ -106,21 +106,55 @@ internal class ClassRegistrationForRmi(ifaceClass: Class<*>,
|
||||
override fun register(kryo: KryoExtra, rmi: RmiHolder) {
|
||||
// we override this, because we ALWAYS will call our RMI registration!
|
||||
|
||||
// have to get the ID for the interface (if it exists)
|
||||
val registration = kryo.classResolver.getRegistration(clazz) // this is ifaceClass, and must match what is defined on the rmi client
|
||||
if (implClass == null) {
|
||||
// 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) {
|
||||
id = registration.id
|
||||
|
||||
// override that registration
|
||||
kryo.register(implClass, serializer, id)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// now register the impl class
|
||||
id = kryo.register(implClass, serializer).id
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// have to get the ID for the interface (if it exists)
|
||||
info = if (implClass == null) {
|
||||
"Registered $id -> (RMI-CLIENT) ${clazz.name}"
|
||||
} 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
|
||||
@ -128,16 +162,18 @@ internal class ClassRegistrationForRmi(ifaceClass: Class<*>,
|
||||
rmi.idToIface[id] = clazz
|
||||
|
||||
// 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.idToImpl[id] = implClass
|
||||
}
|
||||
}
|
||||
|
||||
override fun getInfoArray(): Array<Any> {
|
||||
// the info array has to match for the INTERFACE (not the impl!)
|
||||
return if (implClass == null) {
|
||||
arrayOf(4, id, clazz.name, serializer!!::class.java.name, "")
|
||||
} 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".
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
@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(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." }
|
||||
}
|
||||
|
||||
classesToRegister.add(ClassRegistrationForRmi(ifaceClass, implClass, rmiServerSerializer))
|
||||
return this
|
||||
@ -332,7 +340,6 @@ open class Serialization(private val references: Boolean = true, private val fac
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -459,7 +466,18 @@ open class Serialization(private val references: Boolean = true, private val fac
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
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 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.
|
||||
// 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)
|
||||
val implClazzName = bytes[4] as String
|
||||
var implClass: Class<*>? = null
|
||||
val implClassName = bytes[4] as String
|
||||
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 {
|
||||
implClass = Class.forName(implClazzName)
|
||||
implClass = Class.forName(implClassName)
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
}
|
||||
|
||||
// implClass MIGHT BE NULL!
|
||||
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!
|
||||
initKryo()
|
||||
|
||||
// now do a round-trip through the server serialization to make sure our byte arrays are THE SAME.
|
||||
initializeClassRegistrations()
|
||||
|
||||
// verify the registration ID data is THE SAME!
|
||||
return savedRegistrationDetails.contentEquals(kryoRegistrationDetailsFromServer)
|
||||
// now do a round-trip through the class registrations
|
||||
return initializeClassRegistrations()
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user