RMI cleanup/polish

This commit is contained in:
nathan 2017-09-25 23:15:32 +02:00
parent f8d71b96dd
commit 6c97567d04
3 changed files with 31 additions and 102 deletions

View File

@ -38,11 +38,11 @@ import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.serializers.CollectionSerializer;
import com.esotericsoftware.kryo.serializers.FieldSerializer;
import com.esotericsoftware.kryo.util.IdentityMap;
import com.esotericsoftware.kryo.util.IntMap;
import com.esotericsoftware.kryo.util.MapReferenceResolver;
import dorkbox.network.connection.ping.PingMessage;
import dorkbox.network.rmi.ClassDefinitions;
import dorkbox.network.rmi.InvocationHandlerSerializer;
import dorkbox.network.rmi.InvocationResultSerializer;
import dorkbox.network.rmi.InvokeMethod;
@ -178,7 +178,8 @@ class CryptoSerializationManager implements dorkbox.network.util.CryptoSerializa
// used to track which interface -> implementation, for use by RMI
private final IntMap<Class<?>> rmiIdToImpl = new IntMap<Class<?>>();
private final IntMap<Class<?>> rmiIdToIface = new IntMap<Class<?>>();
private final ClassDefinitions classDefinitions = new ClassDefinitions();
private final IdentityMap<Class<?>, Class<?>> rmiIfacetoImpl = new IdentityMap<Class<?>, Class<?>>();
private final IdentityMap<Class<?>, Class<?>> rmiImplToIface = new IdentityMap<Class<?>, Class<?>>();
/**
* By default, the serialization manager will compress+encrypt data to connections with remote IPs, and only compress on the loopback IP
@ -272,6 +273,7 @@ class CryptoSerializationManager implements dorkbox.network.util.CryptoSerializa
int id = kryo.register(remoteImplClass.implClass, remoteObjectSerializer).getId();
// sets up the RMI, so when we receive the iface class from the client, we know what impl to use
// if this is over-written, we don't care.
rmiIdToImpl.put(id, remoteImplClass.implClass);
rmiIdToIface.put(id, remoteImplClass.ifaceClass);
}
@ -403,7 +405,15 @@ class CryptoSerializationManager implements dorkbox.network.util.CryptoSerializa
classesToRegister.add(new RemoteImplClass(ifaceClass, implClass));
// this MUST BE UNIQUE otherwise unexpected things can happen.
classDefinitions.set(ifaceClass, implClass);
Class<?> a = this.rmiIfacetoImpl.put(ifaceClass, implClass);
Class<?> b = this.rmiImplToIface.put(implClass, ifaceClass);
// this MUST BE UNIQUE otherwise unexpected things can happen.
if (a != null || b != null) {
throw new IllegalArgumentException("Unable to override interface (" + ifaceClass + ") and implementation (" + implClass + ") " +
"because they have already been overridden by something else. It is critical that they are" +
" both unique per JVM");
}
return this;
}
@ -439,7 +449,9 @@ class CryptoSerializationManager implements dorkbox.network.util.CryptoSerializa
public synchronized
void finishInit() {
initialized = true;
// initialize the kryo pool with at least 1 kryo instance. This ALSO makes sure that all of our class registration is done correctly
// initialize the kryo pool with at least 1 kryo instance. This ALSO makes sure that all of our class registration is done
// correctly and (if not) we are are notified on the initial thread (instead of on the network udpate thread)
kryoPool.put(takeKryo());
}
@ -461,6 +473,19 @@ class CryptoSerializationManager implements dorkbox.network.util.CryptoSerializa
return rmiIdToIface.get(objectId);
}
/**
* Gets the RMI implementation based on the specified ID (which is the ID for the registered interface)
*
* @param objectId ID of the registered interface, which will map to the corresponding implementation.
*
* @return the implementation for the interface, or null
*/
@Override
public
Class<?> getRmiImpl(int objectId) {
return rmiIdToImpl.get(objectId);
}
/**
* Gets the RMI implementation based on the specified interface
*
@ -469,7 +494,7 @@ class CryptoSerializationManager implements dorkbox.network.util.CryptoSerializa
@Override
public
Class<?> getRmiImpl(Class<?> iface) {
return classDefinitions.get(iface);
return rmiIfacetoImpl.get(iface);
}
/**
@ -480,19 +505,7 @@ class CryptoSerializationManager implements dorkbox.network.util.CryptoSerializa
@Override
public
Class<?> getRmiIface(Class<?> implementation) {
return classDefinitions.getReverse(implementation);
}
/**
* Gets the RMI implementation based on the specified ID (which is the ID for the registered interface)
*
* @param objectId ID of the registered interface, which will map to the corresponding implementation.
* @return the implementation for the interface, or null
*/
@Override
public
Class<?> getRmiImpl(int objectId) {
return rmiIdToImpl.get(objectId);
return rmiImplToIface.get(implementation);
}
/**

View File

@ -1,81 +0,0 @@
/*
* Copyright 2016 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.network.rmi;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import com.esotericsoftware.kryo.util.IdentityMap;
/**
* Uses the "single writer principle" for fast access
*/
public
class ClassDefinitions {
// not concurrent because they are setup during system initialization
private volatile IdentityMap<Class<?>, Class<?>> overriddenMethods = new IdentityMap<Class<?>, Class<?>>();
private volatile IdentityMap<Class<?>, Class<?>> overriddenReverseMethods = new IdentityMap<Class<?>, Class<?>>();
private static final AtomicReferenceFieldUpdater<ClassDefinitions, IdentityMap> overriddenMethodsREF =
AtomicReferenceFieldUpdater.newUpdater(ClassDefinitions.class,
IdentityMap.class,
"overriddenMethods");
private static final AtomicReferenceFieldUpdater<ClassDefinitions, IdentityMap> overriddenReverseMethodsREF =
AtomicReferenceFieldUpdater.newUpdater(ClassDefinitions.class,
IdentityMap.class,
"overriddenReverseMethods");
public
ClassDefinitions() {
}
/**
* access a snapshot of the overridden methods (single-writer-principle)
*/
public
Class<?> get(final Class<?> type) {
//noinspection unchecked
final IdentityMap<Class<?>, Class<?>> identityMap = overriddenMethodsREF.get(this);
return identityMap.get(type);
}
/**
* access a snapshot of the overridden methods (single-writer-principle)
*/
public
Class<?> getReverse(final Class<?> type) {
//noinspection unchecked
final IdentityMap<Class<?>, Class<?>> identityMap = overriddenReverseMethodsREF.get(this);
return identityMap.get(type);
}
/**
* @throws IllegalArgumentException if the iface/impl have previously been overridden
*/
// synchronized to make sure only one writer at a time
public synchronized
void set(final Class<?> ifaceClass, final Class<?> implClass) {
Class<?> a = this.overriddenMethods.put(ifaceClass, implClass);
Class<?> b = this.overriddenReverseMethods.put(implClass, ifaceClass);
// this MUST BE UNIQUE otherwise unexpected things can happen.
if (a != null || b != null) {
throw new IllegalArgumentException("Unable to override interface (" + ifaceClass + ") and implementation (" + implClass + ") " +
"because they have already been overridden by something else. It is critical that they are" +
" both unique per JVM");
}
}
}

View File

@ -104,12 +104,9 @@ class RmiProxyHandler implements InvocationHandler {
byte responseID = invokeMethodResult.responseID;
if (invokeMethodResult.objectID != objectID) {
// System.err.println("FAILED: " + responseID);
// logger.trace("{} FAILED to received data: {} with id ({})", connection, invokeMethodResult.result, invokeMethodResult.responseID);
return;
}
// logger.trace("{} received data: {} with id ({})", connection, invokeMethodResult.result, invokeMethodResult.responseID);
synchronized (this) {
if (RmiProxyHandler.this.pendingResponses[responseID]) {
RmiProxyHandler.this.responseTable[responseID] = invokeMethodResult;