package org.async.rmi;
import org.async.rmi.client.RMIInvocationHandler;
import org.async.rmi.modules.Exporter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Proxy;
import java.net.UnknownHostException;
import java.rmi.Remote;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Created by Barak Bar Orion
* 05/10/14.
* Export Remote Object using DynamicProxy.
*/
public class DynamicExporter implements Exporter {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = LoggerFactory.getLogger(DynamicExporter.class);
private Map<Long, Remote> exportedObjects;
public DynamicExporter() {
exportedObjects = new ConcurrentHashMap<>();
}
@Override
public <T extends Remote> T export(T impl) throws InterruptedException, UnknownHostException {
if (impl instanceof Exported) {
return impl;
}
Modules.getInstance().getTransport().listen(impl.getClass().getClassLoader());
T proxy = createProxy(impl, 0);
exportedObjects.put(((Exported) proxy).getObjectId(), proxy);
return proxy;
}
@Override
public <T extends Remote> T export(T impl, long objectId) throws InterruptedException, UnknownHostException {
if (impl instanceof Exported) {
return impl;
}
Modules.getInstance().getTransport().listen(impl.getClass().getClassLoader());
T proxy = createProxy(impl, objectId);
exportedObjects.put(((Exported) proxy).getObjectId(), proxy);
return proxy;
}
/**
* {@inheritDoc}
*/
@Override
public boolean unexport() {
for (Long objectId : exportedObjects.keySet()) {
exportedObjects.remove(objectId);
Modules.getInstance().getObjectRepository().remove(objectId);
}
return true;
}
@SuppressWarnings("SpellCheckingInspection")
@Override
public boolean unexport(Remote obj) {
if (obj instanceof Exported) {
long objectId = ((Exported) obj).getObjectId();
if (obj.equals(exportedObjects.get(objectId))) {
exportedObjects.remove(objectId);
Modules.getInstance().getObjectRepository().remove(objectId);
}
}
return true;
}
private <T extends Remote> T createProxy(Remote impl, long objectId) throws UnknownHostException, InterruptedException {
Class[] remoteInterfaces = extractRemoteInterfaces(impl.getClass());
RMIInvocationHandler handler = new RMIInvocationHandler(impl, remoteInterfaces, objectId);
//noinspection unchecked
return (T) Proxy.newProxyInstance(impl.getClass().getClassLoader(), remoteInterfaces, handler);
}
private Class[] extractRemoteInterfaces(Class cls) {
ArrayList<Class<?>> found = new ArrayList<>();
found.add(Exported.class);
while (!cls.equals(Object.class)) {
for (Class cl : cls.getInterfaces()) {
if (Remote.class.isAssignableFrom(cl)) {
found.add(cl);
}
}
cls = cls.getSuperclass();
}
return found.toArray(new Class[found.size()]);
}
}