package de.desy.tine.client;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.ConcurrentLinkedQueue;
import de.desy.tine.dataUtils.TDataType;
import de.desy.tine.definitions.TErrorList;
import de.desy.tine.definitions.TMode;
import de.desy.tine.headers.TSubscription;
import de.desy.tine.server.logger.DbgLog;
import de.desy.tine.server.logger.MsgLog;
public class TMcaLink implements TLinkCallback
{
private static TLinkFactory tlf = null;
private static TLinkFactory getLinkFactory()
{
if (tlf == null) tlf = TLinkFactory.getInstance();
return tlf;
}
String ctx;
String srv;
String prp;
String dev;
int ndevices;
//LinkedList <TLink>lnks = new LinkedList<TLink>();
ConcurrentLinkedQueue <TLink>lnks = new ConcurrentLinkedQueue<TLink>();
TLink parent;
public TLink getParent() { return parent; }
public static boolean revertOnLinkTimeout = true;
public TMcaLink(TLink linkItem,int length)
{
ctx = new String(linkItem.getContext());
srv = new String(linkItem.getDeviceServer());
prp = new String(linkItem.getProperty());
ndevices = length;
// TDataType dt = new TDataType(length,linkItem.dOutput.getFormat());
// String tgt = "/"+ctx+"/"+srv+"/#0";
// parent = new TLink(tgt,prp,dt,linkItem.dInput,linkItem.devAccess);
// if (TLinkFactory.debugLevel > 2) DbgLog.log("TMcaLink", "establish parent MCA Link (id "+parent.linkId+"): isBound = "+(parent.getBoundLink() == null ? "false":"true"));
// int lid = parent.attach(linkItem.getSubscription().mode, this, linkItem.getLinkPollingInterval());
// if (lid < 0)
// {
// MsgLog.log("TMcaLink", "could not create mca parent link !",-lid,null,0);
// //parent.linkStatus;
// }
}
public TMcaLink(TLink linkItem, String devName, int length)
{
ctx = new String(linkItem.getContext());
srv = new String(linkItem.getDeviceServer());
prp = new String(linkItem.getProperty());
dev = new String(devName);
linkItem.setMcaDevice(devName);
ndevices = length;
TDataType dt = new TDataType(length,linkItem.dOutput.getFormat());
String tgt = "/"+ctx+"/"+srv+"/"+dev;
try
{
parent = new TLink(tgt,prp,dt,linkItem.dInput,linkItem.devAccess);
} catch (Exception ignore) {} // let the status code propagate
MsgLog.log("TMcaLink", "establish parent MCA Link (id "+parent.linkId+"): isBound = "+(parent.getBoundLink() == null ? "false":"true"),0,null,2);
short mode = linkItem.getSubscription().mode;
mode &= ~(TMode.CM_WAIT);
int lid = parent.attach(mode, this, linkItem.getLinkPollingInterval());
if (lid < 0)
{
MsgLog.log("TMcaLink", "could not create mca parent link !",-lid,null,0);
}
}
public void remove(TLink lnk)
{
synchronized(lnks)
{
String p = parent == null ? "parent unknown" : parent.getFullDeviceNameAndProperty();
MsgLog.log("TMcaLink.remove", "remove "+lnk.getFullDeviceNameAndProperty()+" from McaLink "+p,TErrorList.property_is_mca,null,1);
lnks.remove(lnk);
}
}
public void add(TLink lnk)
{
if (TLinkFactory.isRunningAsServer())
{ // remove any link error alarms that might be lingering
TLinkFactory tf = TLinkFactory.getInstance();
if (tf.getAutoLinkErrorAlarms())
tf.getEquipmentModuleFactory().clearFecLinkErrorAlarm(lnk);
}
synchronized(lnks)
{
if (lnks.contains(lnk)) return;
String p = parent == null ? "parent unknown" : parent.getFullDeviceNameAndProperty();
MsgLog.log("TMcaLink.add", "add "+lnk.getFullDeviceNameAndProperty()+" to McaLink "+p,TErrorList.property_is_mca,null,1);
lnks.add(lnk);
}
}
public void callback(TLink link)
{
int idx;
synchronized(lnks)
{
boolean backout = false;
boolean trace = false;
if (link.linkStatus == TErrorList.reset_mca_property)
{
MsgLog.log("TMcaLink.callback","received reset mca property signal for "+
link.getFullDeviceNameAndProperty(),link.linkStatus, null,1);
backout = true;
}
if (link.linkStatus == TErrorList.link_not_open &&
link.linkTimeouts > TLinkFactory.RETRY_THRESHOLD*5 &&
revertOnLinkTimeout) backout = true;
if (backout)
{ // server seems to have disappeared => revert to original conditions
MsgLog.log("TMcaLink","Mapped MCA Link " + "/"+ctx+"/"+srv+"/"+dev+"["+prp+"] has gone down : revert to original conditions",TErrorList.link_error,null,0);
TSubscription sub;
for (TLink lnk : lnks)
{
trace = TLinkFactory.traceKey != null && lnk.isTraceLink();
if (trace)
{
lnk.traceLink("TMcaLink.callback", "MCA element ("+ lnk.linkId+") is separating from parent");
if (lnk.hasDependencies())
lnk.traceLink("TMcaLink.callback", "MCA element has dependencies");
}
lnk.setMcaIndex(0);
lnk.setMcaDevice(null);
if (lnk.primary != null)
{
int lid = lnk.linkId;
lnk.bindToParentLink(lnk.primary,null,null);
lnk.linkId = lid; // override bindToParentLink (this bound link is now in the link table !)
if (trace) lnk.traceLink("TMcaLink.callback", "MCA element is now dependent on link "+lnk.primary.linkId);
}
else
{
lnk.setBoundLink(null);
if ((sub=lnk.getSubscription()) == null)
{
if (trace) lnk.traceLink("TMcaLink.callback", "has null subscription !");
continue;
}
sub.mode = link.getSubscription().mode;
sub.linkLastTime = 0;
if (trace) lnk.traceLink("TMcaLink.callback", "mode changed to "+TMode.toString(sub.mode));
}
}
if (link.dependencies != null) link.dependencies.clear();
link.close();
TLinkFactory.rmvMcaLink(this);
return;
}
TLink lnk = null;
Iterator<TLink> itr = lnks.iterator();
while (itr.hasNext())
{
lnk = itr.next();
if (lnk.sub != null && lnk.sub.mode == TMode.CM_CANCEL)
{ // canceled in a callback ?
itr.remove();
continue;
}
trace = TLinkFactory.traceKey != null && lnk.isTraceLink();
idx = lnk.getMcaIndex() - 1;
if (idx >= 0 && idx < link.dOutput.dArrayLength)
{
if (TErrorList.hasData(link.linkStatus))
lnk.dOutput.dataCopy(link.dOutput, idx, true);
lnk.hasNotifiedOnce = link.hasNotifiedOnce;
lnk.hasObtainedStatus = true;
lnk.linkStatus = link.linkStatus;
lnk.linkStatusSource = link.linkStatusSource;
lnk.dOutput.dCompletionLength = 1;
lnk.dOutput.numblks = lnk.dOutput.blknum = lnk.dOutput.blksin = 1;
lnk.dOutput.setDataTimeStamp(link.dOutput.getDataTimeStamp());
lnk.dOutput.setSystemDataStamp(link.dOutput.getSystemDataStamp());
lnk.dOutput.setUserDataStamp(link.dOutput.getUserDataStamp());
lnk.notifyPending = false;
if (lnk.isGrouped())
{
if (lnk.getGroup().getNumberPending() > 0) continue;
if (TLinkFactory.debugLevel > 0) DbgLog.log("TMcaLink.callback","all members of group have updated");
lnk.getGroup().reset();
}
lnk.notifyPending = true;
if (TLinkFactory.debugLevel > 3) DbgLog.log("TMcaLink.callback", "fire callback for link "+lnk.getFullDeviceName()+" (id "+lnk.linkId+")");
//TLinkFactory.getInstance().fireCallbackEvent("TMcaLink", lnk);
if (lnk.hasDependencies())
{ // chained dependencies ? -> do them first
if (trace) lnk.traceLink("TMcaLink.callback", "run thru dependency list");
TLink xlnk;
TDataType xlnkData;
LinkedList<TLink> xlst = lnk.getDependencies();
for (int k=0; k < xlst.size(); k++)
{
xlnk = (TLink)xlst.get(k);
if (xlnk == null || xlnk.sub == null) continue;
if (!xlnk.active) continue;
if ((xlnkData=xlnk.getOutputDataObject()) != null)
{
xlnkData.dataCopy(lnk.dOutput);
xlnkData.setDataTimeStamp(lnk.dOutput.getDataTimeStamp());
}
xlnk.sub.linkLastTime = lnk.sub.linkLastTime;
xlnk.linkStatus = lnk.linkStatus;
xlnk.linkStatusSource = link.linkStatusSource;
if (trace) lnk.traceLink("TMcaLink.callback", "fire dependent callback for link "+xlnk.linkId);
getLinkFactory().fireCallbackEvent("TMcaLink",xlnk);
}
}
if (!lnk.isCancelledWithDependencies())
{
if (trace) lnk.traceLink("TMcaLink.callback", "firing single element callback for link "+lnk.linkId);
getLinkFactory().fireCallbackEvent("TMcaLink",lnk);
}
}
}
}
}
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((ctx == null) ? 0 : ctx.hashCode());
result = prime * result + ((prp == null) ? 0 : prp.hashCode());
result = prime * result + ((srv == null) ? 0 : srv.hashCode());
return result;
}
public boolean equals(Object obj)
{
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
TMcaLink other = (TMcaLink) obj;
if (ctx == null)
{
if (other.ctx != null) return false;
}
else if (ctx.compareToIgnoreCase(other.ctx) != 0) return false;
if (prp == null)
{
if (other.prp != null) return false;
}
else if (prp.compareToIgnoreCase(other.prp) != 0) return false;
if (srv == null)
{
if (other.srv != null) return false;
}
else if (srv.compareToIgnoreCase(other.srv) != 0) return false;
return true;
}
}