package org.jboss.ha.framework.server;
import java.lang.ref.SoftReference;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetAddress;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
import java.rmi.server.RemoteStub;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jboss.ha.framework.interfaces.HAPartition;
import org.jboss.ha.framework.interfaces.HARMIClient;
import org.jboss.ha.framework.interfaces.HARMIProxy;
import org.jboss.ha.framework.interfaces.HARMIResponse;
import org.jboss.ha.framework.interfaces.HARMIServer;
import org.jboss.ha.framework.interfaces.LoadBalancePolicy;
import org.jboss.invocation.MarshalledInvocation;
import org.jboss.logging.Logger;
import org.jboss.net.sockets.DefaultSocketFactory;
public class HARMIServerImpl
implements HARMIServer
{
protected Object handler;
protected Map invokerMap = new HashMap();
protected org.jboss.logging.Logger log;
protected RemoteStub rmistub;
protected Object stub;
protected String key;
protected Class intf;
protected RefreshProxiesHATarget target;
public HARMIServerImpl(HAPartition partition,
String replicantName,
Class intf,
Object handler,
int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
throws Exception
{
this(partition,
replicantName,
intf,
handler,
port,
csf,
ssf,
null);
}
public HARMIServerImpl(HAPartition partition,
String replicantName,
Class intf,
Object handler,
int port,
RMIClientSocketFactory clientSocketFactory,
RMIServerSocketFactory serverSocketFactory,
InetAddress bindAddress)
throws Exception
{
this.handler = handler;
this.log = Logger.getLogger(this.getClass());
this.intf = intf;
this.key = partition.getPartitionName() + "/" + replicantName;
Class[] ifaces = handler.getClass().getInterfaces();
for (int i = 0; i < ifaces.length; i++)
{
Map tmp = MarshalledInvocation.methodToHashesMap(ifaces[i]);
invokerMap.putAll(tmp);
}
if( bindAddress != null )
{
if( serverSocketFactory == null )
serverSocketFactory = new DefaultSocketFactory(bindAddress);
else
{
try
{
Class[] parameterTypes = {String.class};
Class ssfClass = serverSocketFactory.getClass();
Method m = ssfClass.getMethod("setBindAddress", parameterTypes);
Object[] args = {bindAddress.getHostAddress()};
m.invoke(serverSocketFactory, args);
}
catch (NoSuchMethodException e)
{
log.warn("Socket factory does not support setBindAddress(String)");
}
catch (Exception e)
{
log.warn("Failed to setBindAddress="+bindAddress+" on socket factory", e);
}
}
}
this.rmistub = (RemoteStub)UnicastRemoteObject.exportObject(this, port, clientSocketFactory, serverSocketFactory); this.target = new RefreshProxiesHATarget(partition, replicantName, rmistub, HATarget.ENABLE_INVOCATIONS);
HARMIServer.rmiServers.put(key, this);
}
public HARMIServerImpl(HAPartition partition, String replicantName, Class intf, Object handler) throws Exception
{
this(partition, replicantName, intf, handler, 0, null, null);
}
public Object createHAStub(LoadBalancePolicy policy)
{
HARMIClient client = new HARMIClient(target.getReplicants(),
target.getCurrentViewId (), policy, key, handler);
this.target.addProxy (client);
return Proxy.newProxyInstance(
intf.getClassLoader(),
new Class[]{ intf, HARMIProxy.class },
client);
}
public void destroy()
{
try
{
target.destroy();
HARMIServer.rmiServers.remove(key);
UnicastRemoteObject.unexportObject(this, true);
} catch (Exception e)
{
log.error("failed to destroy", e);
}
}
public HARMIResponse invoke(long clientViewId, MarshalledInvocation mi)
throws Exception
{
mi.setMethodMap(invokerMap);
Method method = mi.getMethod();
try
{
HARMIResponse rsp = new HARMIResponse();
if (clientViewId != target.getCurrentViewId())
{
rsp.newReplicants = new ArrayList(target.getReplicants());
rsp.currentViewId = target.getCurrentViewId();
}
rsp.response = method.invoke(handler, mi.getArguments());
return rsp;
}
catch (IllegalAccessException iae)
{
throw iae;
}
catch (IllegalArgumentException iae)
{
throw iae;
}
catch (java.lang.reflect.InvocationTargetException ite)
{
throw (Exception)ite.getTargetException();
}
}
public List getReplicants() throws Exception
{
return target.getReplicants();
}
public Object getLocal() throws Exception
{
return handler;
}
public class RefreshProxiesHATarget extends HATarget
{
protected ArrayList generatedProxies;
public RefreshProxiesHATarget(HAPartition partition,
String replicantName,
java.io.Serializable target,
int allowInvocations)
throws Exception
{
super (partition, replicantName, target, allowInvocations);
}
public void init() throws Exception
{
super.init ();
generatedProxies = new ArrayList ();
}
public synchronized void addProxy (HARMIClient client)
{
SoftReference ref = new SoftReference(client);
generatedProxies.add (ref);
}
public synchronized void replicantsChanged(String key, List newReplicants, int newReplicantsViewId)
{
super.replicantsChanged (key, newReplicants, newReplicantsViewId);
int max = generatedProxies.size ();
ArrayList trash = new ArrayList();
for (int i=0; i<max; i++)
{
SoftReference ref = (SoftReference)generatedProxies.get (i);
HARMIClient proxy = (HARMIClient)ref.get ();
if (proxy == null)
{
trash.add (ref);
}
else
{
proxy.updateClusterInfo (this.replicants, this.clusterViewId);
}
}
if (trash.size () > 0)
generatedProxies.removeAll (trash);
}
}
}