/*
* @@COPYRIGHT@@
*/
package com.cosylab.acs.maci.plug;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import org.omg.CORBA.Any;
import org.omg.CORBA.Object;
import org.omg.CORBA.Policy;
import org.omg.CORBA.SetOverrideType;
import org.omg.CORBA.TIMEOUT;
import org.omg.CORBA.TRANSIENT;
import org.omg.Messaging.RELATIVE_RT_TIMEOUT_POLICY_TYPE;
import alma.ACSErrTypeCommon.wrappers.AcsJCORBAProblemEx;
import alma.acs.util.IorParser;
import alma.acs.util.UTCUtility;
import com.cosylab.acs.maci.AuthenticationData;
import com.cosylab.acs.maci.Client;
import com.cosylab.acs.maci.ClientType;
import com.cosylab.acs.maci.ComponentInfo;
import com.cosylab.acs.maci.ImplLang;
import com.cosylab.acs.maci.MessageType;
import com.cosylab.acs.maci.RemoteException;
import com.cosylab.acs.maci.RemoteTimeoutException;
import com.cosylab.acs.maci.RemoteTransientException;
/**
* CORBA Client Proxy.
*
* @author Matej Sekoranja (matej.sekoranja@cosylab.com)
* @version @@VERSION@@
*/
public class ClientProxy extends CORBAReferenceSerializator implements Client, Serializable
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 5300210586145192795L;
/**
* CORBA reference.
*/
protected si.ijs.maci.Client client;
/**
* Cached serialized reference.
*/
protected String ior;
/**
* Constructor for ClientProxy.
* @param client CORBA reference, non-<code>null</code>.
*/
public ClientProxy(si.ijs.maci.Client client)
{
assert (client != null);
this.client = client;
this.ior = serialize(client);
}
/**
* Convert CORBA ClienType to manager type.
* @param type
* @return
*/
public static ClientType toClientType(si.ijs.maci.ClientType type)
{
if (type == si.ijs.maci.ClientType.CLIENT_TYPE)
return ClientType.CLIENT;
else if (type == si.ijs.maci.ClientType.ADMINISTRATOR_TYPE)
return ClientType.ADMINISTRATOR;
else if (type == si.ijs.maci.ClientType.CONTAINER_TYPE)
return ClientType.CONTAINER;
else
throw new IllegalArgumentException("unsupported client type");
}
/**
* Convert CORBA ImplLang to manager type.
* @param type
* @return
*/
public static ImplLang toImplLang(si.ijs.maci.ImplLangType type)
{
if (type == si.ijs.maci.ImplLangType.JAVA)
return ImplLang.java;
else if (type == si.ijs.maci.ImplLangType.CPP)
return ImplLang.cpp;
else if (type == si.ijs.maci.ImplLangType.PYTHON)
return ImplLang.py;
else
throw new IllegalArgumentException("unsupported implementation language type");
}
/**
* @see com.cosylab.acs.maci.Client#authenticate(long, String)
*/
public AuthenticationData authenticate(long executionId, String question) throws RemoteException
{
try
{
si.ijs.maci.AuthenticationData retVal = client.authenticate(executionId, question);
return new AuthenticationData(
retVal.answer,
toClientType(retVal.client_type),
toImplLang(retVal.impl_lang),
retVal.recover,
UTCUtility.utcOmgToJava(retVal.timestamp),
retVal.execution_id);
}
catch (Exception ex)
{
RemoteException re = new RemoteException("Failed to invoke 'authenticate()' method.", ex);
throw re;
}
}
/**
* @see com.cosylab.acs.maci.Client#components_available(ComponentInfo[])
*/
public void components_available(ComponentInfo[] cobs) throws RemoteException
{
try
{
// invalid info (replacement for null)
final si.ijs.maci.ComponentInfo invalidInfo = new si.ijs.maci.ComponentInfo("<invalid>", "<invalid>", null, "<invalid>", new int[0], 0, "<invalid>", 0, 0, new String[0]);
// transform to CORBA specific
si.ijs.maci.ComponentInfo[] infos = null;
if (cobs != null)
{
infos = new si.ijs.maci.ComponentInfo[cobs.length];
for (int i = 0; i < cobs.length; i++)
if (cobs[i] == null)
infos[i] = invalidInfo;
else
{
Object obj = null;
if (cobs[i].getComponent() != null)
obj = (Object)cobs[i].getComponent().getObject();
String[] interfaces;
if (cobs[i].getInterfaces() != null)
interfaces = cobs[i].getInterfaces();
else
interfaces = new String[0];
infos[i] = new si.ijs.maci.ComponentInfo(
cobs[i].getType(),
cobs[i].getCode(),
obj,
cobs[i].getName(),
cobs[i].getClients().toArray(),
cobs[i].getContainer(),
cobs[i].getContainerName(),
cobs[i].getHandle(),
ManagerProxyImpl.mapAccessRights(cobs[i].getAccessRights()),
interfaces
);
}
}
else
infos = new si.ijs.maci.ComponentInfo[0];
client.components_available(infos);
}
catch (TIMEOUT te)
{
throw new RemoteTimeoutException("Failed to invoke 'components_available()' method due to timeout.", te);
}
catch (TRANSIENT tre)
{
throw new RemoteTransientException("Failed to invoke 'components_available()' method due to transient exception.", tre);
}
catch (Throwable ex)
{
throw new RemoteException("Failed to invoke 'component_available()' method.", ex);
}
}
/**
* @see com.cosylab.acs.maci.Client#components_unavailable(String[])
*/
public void components_unavailable(String[] cobs) throws RemoteException
{
try
{
client.components_unavailable(cobs);
}
catch (TIMEOUT te)
{
throw new RemoteTimeoutException("Failed to invoke 'components_unavailable()' method due to timeout.", te);
}
catch (TRANSIENT tre)
{
throw new RemoteTransientException("Failed to invoke 'components_unavailable()' method due to transient exception.", tre);
}
catch (Throwable ex)
{
throw new RemoteException("Failed to invoke 'component_unavailable()' method.", ex);
}
}
/**
* @see com.cosylab.acs.maci.Client#disconnect()
*/
public void disconnect() throws RemoteException
{
try
{
client.disconnect();
}
catch (TIMEOUT te)
{
throw new RemoteTimeoutException("Failed to invoke 'disconnect()' method due to timeout.", te);
}
catch (TRANSIENT tre)
{
throw new RemoteTransientException("Failed to invoke 'disconnect()' method due to transient exception.", tre);
}
catch (Throwable ex)
{
throw new RemoteException("Failed to invoke 'disconnect()' method.", ex);
}
}
/**
* @see com.cosylab.acs.maci.Client#message(MessageType, String)
*/
public void message(MessageType type, String message)
throws RemoteException
{
try
{
short msgType;
if (type == MessageType.MSG_ERROR)
msgType = si.ijs.maci.Client.MSG_ERROR;
else
msgType = si.ijs.maci.Client.MSG_INFORMATION;
client.message(msgType, message);
}
catch (TIMEOUT te)
{
throw new RemoteTimeoutException("Failed to invoke 'message()' method due to timeout.", te);
}
catch (TRANSIENT tre)
{
throw new RemoteTransientException("Failed to invoke 'message()' method due to transient exception.", tre);
}
catch (Throwable ex)
{
throw new RemoteException("Failed to invoke 'message()' method.", ex);
}
}
/**
* @see com.cosylab.acs.maci.Client#message(MessageType, String)
*/
public void taggedmessage(MessageType type, short id, String message)
throws RemoteException
{
try
{
short msgType;
if (type == MessageType.MSG_ERROR)
msgType = si.ijs.maci.Client.MSG_ERROR;
else
msgType = si.ijs.maci.Client.MSG_INFORMATION;
client.taggedmessage(msgType, id, message);
}
catch (TIMEOUT te)
{
throw new RemoteTimeoutException("Failed to invoke 'tagged_message()' method due to timeout.", te);
}
catch (TRANSIENT tre)
{
throw new RemoteTransientException("Failed to invoke 'tagged_message()' method due to transient exception.", tre);
}
catch (Throwable ex)
{
throw new RemoteException("Failed to invoke 'tagged_message()' method.", ex);
}
}
/**
* @see com.cosylab.acs.maci.Client#name()
*/
public String name() throws RemoteException
{
try
{
return client.name();
}
catch (Exception ex)
{
RemoteException re = new RemoteException("Failed to invoke 'name()' method.", ex);
throw re;
}
}
/**
* ping() CORBA client-side timeout JVM property name.
*/
private static final String NAME_PING_TIMEOUT = "manager.pingCallTimeout";
/**
* Default ping timeout.
*/
private static final double DEFAULT_PING_TIMEOUT_DEFAULT_SEC = 20.0;
private static double pingTimeoutSec = DEFAULT_PING_TIMEOUT_DEFAULT_SEC;
static {
String secValue = System.getProperty(NAME_PING_TIMEOUT);
if (secValue != null)
{
try
{
pingTimeoutSec = Double.parseDouble(secValue);
} catch (Throwable th) {
// noop
}
// at least one second
pingTimeoutSec = Math.max(1.0, pingTimeoutSec);
}
}
/**
* @see com.cosylab.acs.maci.Client#ping()
*/
public boolean ping() throws RemoteException
{
// invalid reference check
if (client == null)
return false;
si.ijs.maci.Client wrappedClient = null;
try
{
// NOTE: JacORB 3.4 returns the new instance
wrappedClient = wrapForRoundtripTimeout(client, pingTimeoutSec);
return wrappedClient.ping();
}
catch (TIMEOUT te)
{
throw new RemoteTimeoutException("Failed to invoke 'ping()' method due to timeout.", te);
}
catch (TRANSIENT tre)
{
throw new RemoteTransientException("Failed to invoke 'ping()' method due to transient exception.", tre);
}
catch (Throwable ex)
{
throw new RemoteException("Failed to invoke 'ping()' method.", ex);
}
finally
{
if (wrappedClient != null)
wrappedClient._release();
}
}
/**
* <p>
* Impl note: The corba spec (v 2.4, 4.3.8.1) describes the difference between
* SetOverrideType.SET_OVERRIDE and SetOverrideType.ADD_OVERRIDE. It is not clear to me (HSO)
* which one should be used, or if there is no practical difference.
* @param corbaRef
* @param timeoutSeconds
* @return
* @throws AcsJCORBAProblemEx
*/
public si.ijs.maci.Client wrapForRoundtripTimeout(si.ijs.maci.Client corbaRef, double timeoutSeconds) throws AcsJCORBAProblemEx {
try
{
org.omg.CORBA.ORB orb = getOrb();
Any rrtPolicyAny = orb.create_any();
rrtPolicyAny.insert_ulonglong(UTCUtility.durationJavaMillisToOmg((long)timeoutSeconds*1000));
Policy p = orb.create_policy(RELATIVE_RT_TIMEOUT_POLICY_TYPE.value, rrtPolicyAny);
org.omg.CORBA.Object ret = corbaRef._set_policy_override (new Policy[]{ p }, SetOverrideType.SET_OVERRIDE);
p.destroy();
return si.ijs.maci.ClientHelper.narrow(ret);
}
catch (Throwable thr) {
AcsJCORBAProblemEx ex2 = new AcsJCORBAProblemEx(thr);
ex2.setInfo("Failed to set the object-level client-side corba roundtrip timeout to " + timeoutSeconds);
throw ex2;
}
}
/**
* Returns the client.
* @return si.ijs.maci.Client
*/
public si.ijs.maci.Client getClient()
{
return client;
}
/**
* Get CORBA host/port string.
* @see com.cosylab.acs.maci.Client#getRemoteLocation()
*/
public String getRemoteLocation() throws RemoteException {
try
{
String[] data = IorParser.parse(ior);
return data[0]+ ":" + data[1];
} catch (Throwable th) {
throw new RemoteException("Failed to extract remote location.", th);
}
}
/**
* We explicitly release the client reference, so that the ClientGIOPConnection can be closed,
* where otherwise it will occupy one of the connector threads until it gets garbage collected,
* possibly leading to the manager lock up described in http://jira.alma.cl/browse/COMP-979
*
* @see com.cosylab.acs.maci.Client#release()
*/
public void release() {
client._release();
}
/**
* Save the state of the <tt>ClientProxy</tt> instance to a stream (that
* is, serialize it).
*/
private void writeObject(ObjectOutputStream stream)
throws IOException
{
stream.writeObject(ior);
}
/**
* Reconstitute the <tt>ClientProxy</tt> instance from a stream (that is,
* deserialize it).
*/
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException
{
try {
ior = (String)stream.readObject();
client = si.ijs.maci.ClientHelper.narrow(deserialize(ior));
}
catch (Exception e) {
// silent here and set reference to null.
// An method after deserialization should clean such invalid reference
client = null;
ior = null;
}
}
/**
* Returns a single-line rendition of this instance into text.
*
* @return internal state of this instance
*/
public String toString()
{
StringBuffer sbuff = new StringBuffer();
sbuff.append("ClientProxy = { ");
sbuff.append("client = '");
sbuff.append(client);
sbuff.append("' }");
return new String(sbuff);
}
/**
* @see java.lang.Object#equals(Object)
*/
public boolean equals(Object obj) {
if (client == null)
return (obj == null);
else if (obj instanceof si.ijs.maci.Client) {
try {
// compare IORs (encoded host, port, object name, ...)
return client.toString().equals(((si.ijs.maci.Client)obj).toString());
//return client._is_equivalent((si.ijs.maci.Client) obj);
} catch (Exception ex) {
return false;
}
} else if (obj instanceof ClientProxy) {
try {
// compare IORs (encoded host, port, object name, ...)
return ior.equals(((ClientProxy) obj).ior);
//return client._is_equivalent(((ClientProxy) obj).getClient());
} catch (Exception ex) {
return false;
}
} else
return false;
}
}