package de.desy.tine.client;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.NoRouteToHostException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import de.desy.tine.addrUtils.*;
import de.desy.tine.bitfieldUtils.*;
import de.desy.tine.console.*;
import de.desy.tine.dataUtils.*;
import de.desy.tine.definitions.*;
import de.desy.tine.endianUtils.*;
import de.desy.tine.headers.*;
import de.desy.tine.io.*;
import de.desy.tine.queryUtils.TQuery;
import de.desy.tine.server.equipment.TEquipmentModuleFactory;
import de.desy.tine.server.logger.*;
import de.desy.tine.server.properties.TMetaProperties;
import de.desy.tine.startup.*;
import de.desy.tine.structUtils.*;
import de.desy.tine.types.*;
/**
* TLinkFactory.java
*
* User interface calls to access available methods from the TLink factory
*
* The available public methods from the TLink factory singleton generally
* involve configuration settings affecting performance, memory (table capacities)
* and behavior.
*/
public class TLinkFactory
{
protected void finalize() throws Throwable
{
MsgLog.log("TLinkFactory","link factory closing down",0,null,0);
super.finalize();
}
public Object ensMutex = new Object();
public static final int TO_THRESHOLD = 10;
public static final int TO_RETRY_THRESHOLD = 2;
public static final long ENS_BACKOFF_THRESHOLD = 5000;
private static TInitializer initializerInstance = TInitializerFactory.getInstance().getInitializer();
private static boolean gSystemRunningStandAlone = false;
public boolean isRunningStandAlone() { return gSystemRunningStandAlone; }
TMetaProperties metaProps = TMetaProperties.getInstance();
private static boolean gAllowNetworkAddressResolution = false;
public void setAllowNetworkAddressResolution(boolean value) { gAllowNetworkAddressResolution = value; }
public boolean allowNeworkAddressResolution() { return gAllowNetworkAddressResolution; }
private static boolean isRichClient = true;
public static boolean isRichClient() { return isRichClient; }
public static void setRichClient(boolean value) { isRichClient = value; }
private static LinkedList<TFilterLink> filterList = new LinkedList<TFilterLink>();
public static void addFilterLink(TFilterLink filter)
{
synchronized(filterList)
{
if (!filterList.contains(filter)) filterList.add(filter);
}
}
public static void rmvFilterLink(TFilterLink filter)
{
if (filter == null) return;
synchronized(filterList)
{
if (!filterList.contains(filter))
{
filter.remove();
filterList.remove(filter);
}
}
}
public static void flushFilterLinks()
{
synchronized(filterList)
{
TFilterLink tfl = null;
Iterator<TFilterLink> it = filterList.iterator();
while (it.hasNext())
{
tfl = it.next();
tfl.remove();
it.remove();
}
}
}
public static void dumpFilterList()
{
dbgPrint("\nCurrent Filter Table (local history/local alarm system):");
synchronized (filterList)
{
TFilterLink tfl;
for (int i=0; i<filterList.size(); i++)
{
tfl = filterList.get(i);
dbgPrint(tfl.toString());
}
}
dbgPrint("");
}
private static Hashtable<String,TMcaLink> mcaLst = new Hashtable<String,TMcaLink>();
public static TMcaLink getMcaLink(String context,String server,String device,String property)
{
synchronized (mcaLst)
{
String key = "/"+context+"/"+server+"/"+device+"["+property+"]";
return mcaLst.get(key);
}
}
public static TMcaLink getMcaLinkForReuse(String context,String server,String device,String property)
{
synchronized (mcaLst)
{
String key = "/"+context+"/"+server+"/"+device+"["+property+"]";
TMcaLink mca = mcaLst.get(key);
if (mca != null)
{
if (mca.parent.removedFromMcaList > 0)
{
MsgLog.log("getMcaLinkForReuse","re-invigorate MCA parent "+mca.parent.getFullDeviceNameAndProperty(),0,null,1);
}
mca.parent.removedFromMcaList = 0;
mca.parent.cancelledWithDependencies = false;
mca.parent.active = true;
}
return mca;
}
}
public static TMcaLink getMcaLink(TLink lnk)
{
synchronized (mcaLst)
{
String key = "/"+lnk.cntName+"/"+lnk.expName+"/"+lnk.devName+"["+lnk.devProperty+"]";
return mcaLst.get(key);
}
}
public static void addMcaLink(TMcaLink lnk)
{
String key = "/"+lnk.ctx+"/"+lnk.srv+"/"+lnk.dev+"["+lnk.prp+"]";
synchronized (mcaLst)
{
if (!mcaLst.containsKey(key))
{
mcaLst.put(key, lnk);
MsgLog.log("TLinkFactory", "add "+key+" to MCA list",TErrorList.property_is_mca,null,1);
}
}
}
public static void rmvMcaLink(TMcaLink lnk)
{
synchronized (mcaLst)
{
String key = "/"+lnk.ctx+"/"+lnk.srv+"/"+lnk.dev+"["+lnk.prp+"]";
MsgLog.log("rmvMcaLink", "remove MCA link from factory",0,null,1);
mcaLst.remove(key);
}
}
public class GlobalInfo
{
public class GlobalRawData
{
byte[] dat = null;
int len;
short fmt;
int dts;
int dtsUSEC;
int sds;
short sts;
GlobalRawData(byte[] data,int length,short format,int timestamp,int timestampUSEC, int systemstamp,short status)
{
len = length; fmt = format;
dts = timestamp; dtsUSEC = timestampUSEC;
sds = systemstamp; sts = status;
int sizeInBytes = len * TFormat.formatSizeOf(fmt);
if (dat == null) dat = new byte[sizeInBytes];
if (data != null)
{
if (data.length < sizeInBytes)
{
MsgLog.log("GlobalInfo.GlobalRawData", "supplied data block too small",TErrorList.buffer_too_small,null,0);
sizeInBytes = data.length;
}
System.arraycopy(data, 0, dat, 0, sizeInBytes);
}
}
void put(byte[] data,int timestamp,int timestampUSEC, int systemstamp,short status)
{
if (data != null)
{
dts = timestamp; dtsUSEC = timestampUSEC;
sds = systemstamp; sts = status;
int sizeInBytes = len * TFormat.formatSizeOf(fmt);
if (data.length < sizeInBytes)
{
MsgLog.log("GlobalInfo.GlobalRawData.put", "supplied data block too small",TErrorList.buffer_too_small,null,0);
sizeInBytes = data.length;
}
System.arraycopy(data, 0, dat, 0, sizeInBytes);
}
}
}
public void updateDataElement(String key,byte[] data,int length,short format,int timestamp,int timestampUSEC,int systemstamp,short status)
{
int idx = keys.indexOf(key);
if (idx < 0) return;
GlobalRawData grd = blks.get(idx);
if (grd == null) return;
if (grd.sts == TErrorList.not_initialized)
blks.set(idx, new GlobalRawData(data,length,format,timestamp,timestampUSEC,systemstamp,status));
else
grd.put(data,timestamp,timestampUSEC,systemstamp,status);
}
public void postDataElement(TLink lnk,String key)
{
int idx = keys.indexOf(key);
GlobalRawData grd = blks.get(idx);
if (grd != null)
{
TGlobalsHdr.postOutputData(lnk, grd.dat, grd.fmt, grd.len, grd.dts, grd.dtsUSEC, grd.sds, 0, grd.sts, TLink.STATUS_LOCAL);
}
}
public boolean hasUpdated = false;
private InetAddress glbAddr;
private String ctx;
public String getContext() { return ctx; }
private ArrayList<String> keys = new ArrayList<String>();
private ArrayList<GlobalRawData> blks = new ArrayList<GlobalRawData>();
private void acquireKeywords(String context)
{
if (context == null) return;
ctx = context;
NAME64[] lst = new NAME64[100];
TDataType tdt = new TDataType(lst);
try
{
TLink lnk = new TLink("/"+ctx+"/GLOBALS","GLOBALS",tdt,null,TAccess.CA_READ);
if (lnk.executeAndClose(500) == 0)
{
int siz = tdt.getCompletionLength();
for (int i=0; i<siz; i++)
{
keys.add(lst[i].getName());
blks.add(new GlobalRawData(null,0,TFormat.CF_NULL,0,0,0,TErrorList.not_initialized));
}
}
}
catch (Exception ignore)
{
}
}
GlobalInfo(String context)
{
acquireKeywords(context);
TSrvEntry tse = new TSrvEntry("GLOBALS",context);
TFecEntry fe = tse.getFecAddr();
glbAddr = fe != null ? fe.fecHost : null;
}
public InetAddress getAddress() { return glbAddr; }
boolean isGlobalKeyword(String key)
{
return keys.contains(key);
}
String[] getGlobalKeywords()
{
return keys.toArray(new String[0]);
}
}
private HashMap<String,GlobalInfo> glbInfo = new HashMap<String,GlobalInfo>();
public boolean isGlobalKeyword(String context,String keyword)
{
if (keyword == null) return false;
if (context == null) context = "SITE";
if (keyword.compareToIgnoreCase("GLOBALS") == 0) return false;
if (keyword.compareToIgnoreCase("SYSTIME") == 0) return true;
if (TQuery.isStockProperty(keyword)) return false;
try
{
if (!glbInfo.containsKey(context))
{
GlobalInfo gi = new GlobalInfo(context);
glbInfo.put(context, gi);
}
return glbInfo.get(context).isGlobalKeyword(keyword);
}
catch (Exception e)
{ // likely an invalid context
MsgLog.log("isGlobalKeyword", "context "+context+" keyword "+keyword+" : "+e.getMessage(),TErrorList.invalid_parameter,e,1);
}
return false;
}
public GlobalInfo getGlobalsInfo(InetAddress addr)
{
return getGlobalsInfo(null,addr);
}
public GlobalInfo getGlobalsInfo(String context,InetAddress addr)
{
GlobalInfo gi = null;
Iterator<GlobalInfo> itr = glbInfo.values().iterator();
while (itr.hasNext())
{
gi = itr.next();
if (context != null && gi.getContext().compareToIgnoreCase(context) != 0) continue;
if (gi.getAddress().equals(addr)) return gi;
}
return null;
}
public class GroupCacheItem
{
private String ctx;
private String grp;
private String srv;
private String dev;
public GroupCacheItem(String context,String group,String server,String device)
{
ctx = context; grp = group; srv = server; dev = device;
}
public void pushItemToCache()
{
TSrvEntry.addServerToGroupCacheFile(ctx,grp,srv);
TSrvEntry.addDeviceToMemberCacheFile(ctx,srv,dev);
}
}
private long lastGroupCacheAddTime = 0;
private static LinkedList<GroupCacheItem> grpCacheLst = new LinkedList<GroupCacheItem>();
public void addItemToGroupCache(String context,String group,String server,String device)
{
lastGroupCacheAddTime = System.currentTimeMillis();
synchronized (grpCacheLst)
{
grpCacheLst.add(new GroupCacheItem(context, group, server, device));
}
}
public void flushGroupCacheItems()
{
synchronized (grpCacheLst)
{
int siz = grpCacheLst.size();
if (siz == 0) return;
long delay = 1000 + 100*siz;
if (System.currentTimeMillis() < lastGroupCacheAddTime + delay) return;
Iterator<GroupCacheItem> itr = grpCacheLst.iterator();
int i;
for (i=0; i<50 && itr.hasNext(); i++)
{
itr.next().pushItemToCache();
itr.remove();
}
MsgLog.log("TLinkFactory.flushGroupCacheItems", "flushed "+i+" group server items to local file cache",0,null,0);
}
}
public boolean ignoreListenerInitialValue = false;
private static Hashtable<TLink, ListenerItem> LsnLnkLst = new Hashtable<TLink, ListenerItem>();
public ListenerItem getListener(TLink lnk)
{
return getListener(lnk,TMode.CM_TIMER,1000);
}
public ListenerItem getListener(TLink lnk,int mode,int interval)
{
if (lnk != null)
{ // no listeners for WRITE access, queries, meta properties, etc.
if (TAccess.isWrite((byte)lnk.devAccess)) return null;
String prp = lnk.getProperty();
if (TQuery.isStockProperty(prp)) return null;
if (TMetaProperties.isMetaProperty(prp)) return null;
}
if (LsnLnkLst.containsKey(lnk))
{
return LsnLnkLst.get(lnk);
}
ListenerItem item = new ListenerItem(lnk,mode,interval);
if (item != null) LsnLnkLst.put(lnk, item);
return item;
}
public void removeListener(TLink lnk)
{
if (!LsnLnkLst.containsKey(lnk)) return;
ListenerItem item = LsnLnkLst.get(lnk);
if (item != null) item.clear();
LsnLnkLst.remove(lnk);
}
public class ListenerItem implements TLinkCallback
{
private TLink lnk = null;
public TLink getListenerLink() { return lnk; }
private int rate = 1000;
public int getPollingInterval() { return rate; }
public void setPollingInterval(int interval)
{
if (interval < 100) interval = 100;
rate = interval;
}
private int mode = TMode.CM_TIMER;
public int getMode() { return mode; }
public void setMode(int mode) { this.mode = mode; }
private int status = TErrorList.not_initialized;
public int getStatus() { return status; }
private long lastread = System.currentTimeMillis();
private int duration = 600;
public void setListenerDuration(int durationInSeconds) { duration = durationInSeconds; }
public int getListenerDuraction() { return duration; }
private boolean isAlive = false;
public boolean isActive() { return isAlive; }
public void keepAlive() { lastread = System.currentTimeMillis(); }
public void stop()
{
if (lnk != null)
{ //run thru the cancel procedure
// if !blockCloseListener: leave it in the table ...
instance.cancel(lnk, lnk.blockCloseListener);
status = TErrorList.not_initialized;
lnk.linkStatus = TErrorList.not_initialized;
isAlive = false;
}
}
public void restart()
{
stop();
start();
}
public void clear()
{
if (lnk != null)
{
stop();
lnk.terminate = true;
lnk = null;
}
}
public void start()
{
if (lnk == null) return;
if (isAlive) return;
int ststmode = mode;
if (!ignoreListenerInitialValue) ststmode |= TMode.CM_WAIT;
int id = lnk.attach(ststmode, this, rate);
isAlive = id < 0 ? false : true;
status = isAlive ? 0 : TErrorList.link_error;
}
public ListenerItem(TLink lnk, int mode, int interval)
{
if (lnk == null) return;
if (lnk.getOutputDataObject() == null)
{
status = TErrorList.not_allowed;
return;
}
if (interval < 100) interval = 100;
this.lnk = lnk;
this.rate = interval;
}
// @Override
public void callback(TLink link)
{
if (duration < 0) return;
long t = System.currentTimeMillis();
if ((int)((t-lastread)/1000) > duration) stop();
}
}
protected static String traceKey = null;
public static String getTraceLinkKey() { return traceKey; }
public static void setTraceLinkKey(String devname, String property)
{
if (devname == null || property == null) traceKey = null;
traceKey = devname+"["+property+"]";
}
public static void setTraceLinkKey(String fullname)
{
if (fullname == null || fullname.length() == 0)
{
traceKey = null;
return;
}
try
{
if (fullname.contains("["))
{
traceKey = fullname;
}
else
{
int idx = fullname.lastIndexOf("/");
String prp = fullname.substring(idx+1);
traceKey = fullname.substring(0, idx)+"["+prp+"]";
}
}
catch (Exception any)
{
traceKey = null;
return;
}
}
public static String getLinkKey(TLink lnk)
{
if (lnk == null) return null;
if (lnk.isRedirected && lnk.rdrKey != null) return lnk.rdrKey;
return "/"+lnk.cntName+"/"+lnk.expName+"/"+lnk.devName+"["+lnk.devProperty+"]";
}
public static boolean isRedirected(String context,String server,String device,String property)
{
if (context == null || server == null || device == null || property == null) return false;
String key = "/"+context+"/"+server+"/"+device+"["+property+"]";
return RdrLst.containsKey(key);
}
public class RedirectedItem
{
private String srcKey; // full name + [property]
private String dstCtx;
private String dstSrv;
private String dstDev;
private String dstPrp;
public boolean destinationEquals(RedirectedItem target)
{
if (target == null) return false;
String tgtCtx = target.getDstContext();
String tgtSrv = target.getDstServer();
String tgtDev = target.getDstDevice();
String tgtPrp = target.getDstProperty();
if (dstCtx != null || tgtCtx != null)
{
if (dstCtx == null || tgtCtx == null) return false;
if (dstCtx.compareToIgnoreCase(tgtCtx) != 0) return false;
}
if (dstSrv != null || tgtSrv != null)
{
if (dstSrv == null || tgtSrv == null) return false;
if (dstSrv.compareToIgnoreCase(tgtSrv) != 0) return false;
}
if (dstDev != null || tgtDev != null)
{
if (dstDev == null || tgtDev == null) return false;
if (dstDev.compareToIgnoreCase(tgtDev) != 0) return false;
}
if (dstPrp != null || tgtPrp != null)
{
if (dstPrp == null || tgtPrp == null) return false;
if (dstPrp.compareToIgnoreCase(tgtPrp) != 0) return false;
}
return true;
}
public RedirectedItem(TLink lnk,String context,String server,String device,String property)
{
srcKey = getLinkKey(lnk);
dstCtx = context == null ? lnk.cntName : context;
dstSrv = server == null ? lnk.expName : server;
dstDev = device == null ? lnk.devName : device;
dstPrp = property == null ? lnk.devProperty : property;
}
public RedirectedItem(String key,String context,String server,String device,String property)
{
srcKey = key;
dstCtx = context;
dstSrv = server;
dstDev = device;
dstPrp = property;
}
public String getDstContext() { return dstCtx; }
public void setDstContext(String context) { this.dstCtx = context; }
public String getDstDevice() { return dstDev; }
public void setDstDevice(String device) { this.dstDev = device; }
public String getDstProperty() { return dstPrp; }
public void setDstProperty(String property) { this.dstPrp = property; }
public String getDstServer() { return dstSrv; }
public void setDstServer(String server) { this.dstSrv = server; }
public String getSrcKey() { return srcKey; }
}
private static Hashtable<String, RedirectedItem> RdrLst = new Hashtable<String, RedirectedItem>();
public void redirectLink(TLink lnk)
{
String key = getLinkKey(lnk);
if (key == null) return;
boolean trace = traceKey != null && lnk.isTraceLink();
if (RdrLst.containsKey(key))
{
String meta = TMetaProperties.getMetaExtension(lnk.devProperty);
RedirectedItem rdr = RdrLst.get(key);
lnk.cntName = rdr.getDstContext();
lnk.expName = rdr.getDstServer();
lnk.devName = rdr.getDstDevice();
lnk.devProperty = rdr.getDstProperty();
if (meta != null && !TMetaProperties.isMetaProperty(lnk.devProperty)
&& lnk.expName.compareToIgnoreCase("HISTORY") != 0)
lnk.devProperty += meta;
lnk.isRedirected = true;
lnk.rdrKey = key;
MsgLog.log("redirectLink", "redirect "+key+" to "+lnk.getFullDeviceNameAndProperty(),0,null,1);
if (trace) lnk.traceLink("redirectLink"," is redirected to "+lnk.getFullDeviceNameAndProperty());
return;
}
// check for wildcard redirection
int idx;
if ((idx=key.indexOf('[')) > 0)
{ // this should always be true !
String wckey = key.substring(0, idx)+"[*]";
if (RdrLst.containsKey(wckey))
{ // redirect any property for the device (e.g. GENS ?)
RedirectedItem rdr = RdrLst.get(wckey);
lnk.cntName = rdr.getDstContext();
lnk.expName = rdr.getDstServer();
lnk.devName = rdr.getDstDevice();
lnk.isRedirected = true;
lnk.rdrKey = wckey;
MsgLog.log("redirectLink", "redirect "+key+" to "+lnk.getFullDeviceNameAndProperty(),0,null,1);
if (trace) lnk.traceLink("redirectLink"," is redirected to "+lnk.getFullDeviceNameAndProperty());
}
}
}
public void flushRedirectionList()
{
RdrLst.clear();
}
public static RedirectedItem getRedirectionInformation(TLink lnk)
{
String key = getLinkKey(lnk);
if (key == null) return null;
return RdrLst.get(key);
}
public void addLinkToRedirectionList(TLink lnk,String context,String server,String device,String property)
{
String key = getLinkKey(lnk);
RdrLst.put(key, new RedirectedItem(lnk,context,server,device,property));
lnk.rdrKey = key;
lnk.isRedirected = true;
}
public void appendRedirectionList(String srcKey,String dstCtx,String dstSrv,String dstDev,String dstPrp)
{
RdrLst.put(srcKey, new RedirectedItem(srcKey,dstCtx,dstSrv,dstDev,dstPrp));
}
public static void dumpRedirectionTable()
{
dbgPrint("\nCurrent Redirection Table");
Iterator<RedirectedItem> itr = RdrLst.values().iterator();
RedirectedItem r;
String rdrItemString;
while (itr.hasNext())
{
r = itr.next();
rdrItemString = r.getSrcKey()+" -> /"+r.getDstContext()+"/"+r.getDstServer()+"/"+r.getDstDevice()+"["+r.getDstProperty()+"]";
dbgPrint(rdrItemString);
}
dbgPrint("");
}
public static void dumpRelinkTable()
{
dbgPrint("\nCurrent Relink Table");
Iterator<RelinkedItem> itr = ReLnkLst.values().iterator();
RelinkedItem r;
String rdrItemString;
TDataType dt;
while (itr.hasNext())
{
r = itr.next();
dt = r.getTargetDataObject();
if (r.sts == TErrorList.invalid_datarequest)
{
rdrItemString = r.getSrcKey()+" "+dt.dArrayLength+" "+TFormat.toString(dt.dFormat)+
" -> "+r.getRelinkDataLength()+" "+TFormat.toString(r.getRelinkDataFormat());
}
else
{
TStructDescription sd;
TBitfield bf;
sd = r.getStructDescription();
bf = r.getBitfield();
if (sd != null) rdrItemString = r.getSrcKey()+" -> "+ sd.getTagName()+" structures";
else if (bf != null) rdrItemString = r.getSrcKey()+" -> "+ bf.getTag()+" bitfields";
else rdrItemString = r.getSrcKey()+" -> unmapped";
}
dbgPrint(rdrItemString);
}
dbgPrint("");
}
public class RelinkedItem
{
private String srcKey; // full name + [property]
private TBitfield dstBf = null;
private TStructDescription dstSd = null;
private String field = null;
private byte[] dstBytes = null;
private TDataType dstTdt = null;
private TDataType tdt = null;
private int len = 0;
private short fmt = TFormat.CF_NULL;
private int sts = 0; // reason for re-link
public int getRelinkReason() { return sts; }
public int getRelinkDataLength() { return len; }
public short getRelinkDataFormat() { return fmt; }
public RelinkedItem(TLink lnk,int len,short fmt)
{
srcKey = getLinkKey(lnk);
if (lnk.dOutput.getFormat() == TFormat.CF_DEFAULT)
{
lnk.dOutput.dFormat = fmt;
lnk.dOutput.dArrayLength = len;
}
dstTdt = lnk.dOutput;
// tdt = new TDataType(len,fmt);
// lnk.dOutput = tdt;
sts = TErrorList.invalid_datarequest;
this.len = len;
this.fmt = fmt;
}
public RelinkedItem(TLink lnk,TBitfield bitfield,String field)
{
srcKey = getLinkKey(lnk);
dstBf = bitfield;
this.field = field;
if (lnk.dOutput.dFormat == TFormat.CF_DEFAULT) lnk.dOutput.dArrayLength = 1;
lnk.dOutput.dFormat = TFormat.getBitfieldFormat(lnk.dOutput.dFormat);
sts = TErrorList.has_bitfield_tag;
this.len = lnk.dOutput.dArrayLength;
this.fmt = lnk.dOutput.dFormat;
}
public TBitfield getBitfield() { return dstBf; }
public TStructDescription getStructDescription() { return dstSd; }
public String getSrcKey() { return srcKey; }
public TDataType getDataObject() { return tdt; }
public TDataType getTargetDataObject() { return dstTdt; }
public String getField() { return field; }
public void setDestination(TLink lnk)
{
if (sts == TErrorList.invalid_datarequest)
{
if (lnk.dOutput.getFormat() == TFormat.CF_DEFAULT)
{
lnk.dOutput.dArrayLength = len;
lnk.dOutput.dFormat = fmt;
}
dstTdt = lnk.dOutput;
tdt = new TDataType(len,fmt);
lnk.dOutput = tdt;
return;
}
if (lnk == null || dstSd == null || field == null) return;
if (lnk.dOutput.getFormat() == TFormat.CF_DEFAULT)
{
lnk.dOutput.dFormat = dstSd.getField(field).getFormat();
lnk.dOutput.dArrayLength = 1;
}
dstTdt = lnk.dOutput;
int slen = dstSd.getRawLength();
if (dstTdt.dArrayLength > tdt.dArrayLength/slen)
{
dstBytes = new byte[slen*lnk.dOutput.getArrayLength()];
tdt = new TDataType(dstBytes,dstSd.getTagName());
}
}
public RelinkedItem(TLink lnk,TStructDescription structDesc,String field)
{
srcKey = getLinkKey(lnk);
dstSd = structDesc;
this.field = field;
if (lnk.dOutput.getFormat() == TFormat.CF_DEFAULT)
{
lnk.dOutput.dFormat = dstSd.getField(field).getFormat();
lnk.dOutput.dArrayLength = 1;
}
dstTdt = lnk.dOutput;
dstBytes = new byte[dstSd.getRawLength()*lnk.dOutput.getArrayLength()];
tdt = new TDataType(dstBytes,dstSd.getTagName());
sts = TErrorList.has_structure_tag;
this.len = lnk.dOutput.dArrayLength;
this.fmt = lnk.dOutput.dFormat;
}
}
private static Hashtable<String, RelinkedItem> ReLnkLst = new Hashtable<String, RelinkedItem>();
public void reLinkLink(TLink lnk)
{
String key = getLinkKey(lnk);
if (key == null) return;
boolean trace = traceKey != null && lnk.isTraceLink();
if (ReLnkLst.containsKey(key))
{
RelinkedItem rlnk = ReLnkLst.get(key);
switch (rlnk.getRelinkReason())
{
case TErrorList.invalid_datarequest:
lnk.mapInvalidDataRequest();
if (trace) lnk.traceLink("reLinkLink", "remapping invalid data request");
break;
case TErrorList.has_bitfield_tag:
if (lnk.dOutput.getTag().length() > 0)
{ // already tagged -> don't relink
return;
}
TBitfield bf = rlnk.getBitfield();
if (bf != null)
{
lnk.mapSingleFieldToBitfield();
if (trace) lnk.traceLink("reLinkLink", "remapping bitfield");
return;
}
case TErrorList.has_structure_tag:
if (lnk.dOutput.getTag().length() > 0)
{ // already tagged -> don't relink
return;
}
TStructDescription tsd = rlnk.getStructDescription();
if (tsd != null)
{
//lnk.dOutput = rlnk.getDataObject();
if (lnk.dOutput.getTag().length() == 0) lnk.dOutput.setTag(tsd.getTagName());
lnk.mapSingleFieldToStruct();
if (trace) lnk.traceLink("reLinkLink", "remapping struct field");
}
break;
}
}
}
public void flushReLinkList()
{
ReLnkLst.clear();
}
public RelinkedItem getRelinkedItem(TLink lnk)
{
String key = getLinkKey(lnk);
return ReLnkLst.get(key);
}
public RelinkedItem addLinkToReLinkList(TLink lnk,TBitfield bitfield,String field)
{
String key = getLinkKey(lnk);
RelinkedItem item = null;
if (ReLnkLst.containsKey(key))
{
item = ReLnkLst.get(key);
}
else
{
item = new RelinkedItem(lnk,bitfield,field);
ReLnkLst.put(key, item);
}
lnk.relnkItem = item;
return item;
}
public RelinkedItem addLinkToReLinkList(TLink lnk,TStructDescription structDesc,String field)
{
String key = getLinkKey(lnk);
RelinkedItem item = null;
if (ReLnkLst.containsKey(key))
{
item = ReLnkLst.get(key);
}
else
{
item = new RelinkedItem(lnk,structDesc,field);
ReLnkLst.put(key, item);
}
item.setDestination(lnk);
lnk.relnkItem = item;
return item;
}
public RelinkedItem addLinkToReLinkList(TLink lnk,int len,short fmt)
{
String key = getLinkKey(lnk);
RelinkedItem item = null;
if (ReLnkLst.containsKey(key))
{
item = ReLnkLst.get(key);
}
else
{
item = new RelinkedItem(lnk,len,fmt);
ReLnkLst.put(key, item);
}
item.setDestination(lnk);
lnk.relnkItem = item;
return item;
}
private static Hashtable<String, BlackListedItem> BlackLnkLst = new Hashtable<String, BlackListedItem>();
public class BlackListedItem
{
private String srcKey; // full name + [property]
private int status = 0;
public BlackListedItem(TLink lnk)
{
srcKey = getLinkKey(lnk);
status = lnk.linkStatus;
}
public int getLinkStatus() { return status; }
public String getSrcKey() { return srcKey; }
}
public void addLinkToBlackList(TLink lnk)
{
if (lnk.linkBlacklists++ > 2) return;
String key = getLinkKey(lnk);
BlackLnkLst.put(key, new BlackListedItem(lnk));
if (lnk.linkBlacklists > 1) lnk.linkStatus = TErrorList.link_blacklisted;
}
public boolean isLinkBlackListed(TLink lnk)
{
String key = getLinkKey(lnk);
if (key == null) return false;
return BlackLnkLst.containsKey(key);
}
/**
* Returns the original link status which caused the link to be black listed
*
* @param lnk is the TLink for which the black listed status is desired
* @return the black listed link status (or invalid_link if the link has not been blacklisted)
*/
public int getBlackListedLinkStatus(TLink lnk)
{
String key = getLinkKey(lnk);
if (key != null && BlackLnkLst.containsKey(key))
{
BlackListedItem bllnk = BlackLnkLst.get(key);
return bllnk.getLinkStatus();
}
return TErrorList.invalid_link;
}
public void flushBlackList()
{
if (BlackLnkLst.size() == 0) return;
if (debugLevel > 0) DbgLog.log("flushBlackList","flushing the current link black list");
BlackLnkLst.clear();
for (int i=0; i<numberTLinksInTable; i++)
{
if (linkTable[i] == null) continue;
if (linkTable[i].linkStatus == TErrorList.link_blacklisted)
{
linkTable[i].linkStatus = TErrorList.link_not_open;
linkTable[i].linkBlacklists = 0;
}
}
}
public static enum AccessLockType {
LOCK_UNLOCKED ,
LOCK_PREEMPTIVE,
LOCK_PERSISTENT,
LOCK_ABORT;
}
public class AccessLockListItem implements TLinkCallback
{
private String key;
TLink lockLink;
int lockType;
int lockLinkStatus;
long lockDuration;
long lastSent;
public AccessLockListItem(String context, String server, AccessLockType lockType, int lockDuration)
{
this(context,server,lockType,lockDuration,0);
}
public AccessLockListItem(String context, String server, AccessLockType lockType, int lockDuration,int lockFlags)
{
int lt = lockType.ordinal();
if (lockFlags != 0) lt |= lockFlags;
short[] lvals = new short[2];
lvals[0] = (short)lt;
lvals[1] = (short)lockDuration;
TDataType din = new TDataType(lvals);
TLink lnk = new TLink("/"+context+"/"+server,"ACCESSLOCK",null,din,TAccess.CA_WRITE|TAccess.CA_RETRY);
key = getLinkKey(lnk);
this.lockType = lt;
this.lockDuration = lockDuration;
lockLink = lnk;
}
public void callback(TLink link)
{
lockLinkStatus = link.linkStatus;
if (lockLinkStatus != 0)
{
if (debugLevel > 0)
DbgLog.log("AccessLockListItem","access lock " + key + " : " + link.linkErrString);
}
}
}
private static Hashtable<String, AccessLockListItem> LockedLnkLst = new Hashtable<String, AccessLockListItem>();
/**
* Acquires an access lock to the server specified.
*
* A client application can obtain an access lock to the given server provided the caller
* has WRITE privileges himself. Once the lock is obtained, no other process will be
* allowed WRITE access regardless of any other access control lists. A lock may be
* preemptive (LOCK_PREEMTIVE) or persistent (LOCK_PERSISTENT). Preemptive locks may be
* aborted (LOCK_ABORT) by other callers with WRITE privileges. Persistent locks may not.
*
* @param context is the targeted context of the server
* @param server is the targeted device server
* @param lockType is the desired lock type: one of AccessLockType.LOCK_CANCEL,
* AccessLockType.LOCK_PREEPMTIVE, AccessLockType.LOCK_PERSISTENT or AccessLockType.LOCK_ABORT.
* @param lockDuration is the requested duration of the lock in seconds. This applies only to
* preemptive locks. Persistent locks will ignore this parameter and continue to renew the lock
* until the caller cancels the lock (graceful) or disappears (maximum 60 second wait).
* @return a tine return code
*
* \b example:
*
* \include eg_AccessLock.java
*/
public static int setAccessLock(String context, String server, AccessLockType lockType, int lockDuration)
{
return setAccessLock(context,server,lockType,lockDuration,0);
}
/**
* Acquires an access lock to the server specified.
*
* A client application can obtain an access lock to the given server provided the caller
* has WRITE privileges himself. Once the lock is obtained, no other process will be
* allowed WRITE access regardless of any other access control lists. A lock may be
* preemptive (LOCK_PREEMTIVE) or persistent (LOCK_PERSISTENT). Preemptive locks may be
* aborted (LOCK_ABORT) by other callers with WRITE privileges. Persistent locks may not.
*
* @param context is the targeted context of the server
* @param server is the targeted device server
* @param lockType is the desired lock type: one of AccessLockType.LOCK_CANCEL,
* AccessLockType.LOCK_PREEPMTIVE, AccessLockType.LOCK_PERSISTENT or AccessLockType.LOCK_ABORT.
* @param lockDuration is the requested duration of the lock in seconds. This applies only to
* preemptive locks. Persistent locks will ignore this parameter and continue to renew the lock
* until the caller cancels the lock (graceful) or disappears (maximum 60 second wait).
* @param lockFlags can contain optional access lock flags such as LOCK_XREAD (exclusive read).
* @return a tine return code
*/
public static int setAccessLock(String context, String server, AccessLockType lockType, int lockDuration,int lockFlags)
{
AccessLockListItem all;
String key = "/"+context+"/"+server+"/[ACCESSLOCK]";
if (LockedLnkLst.containsKey(key))
{ // already have a lock
all = LockedLnkLst.get(key);
}
else
{
all = TLinkFactory.getInstance().new AccessLockListItem(context,server,lockType,lockDuration,lockFlags);
if (lockType.ordinal() > 0) LockedLnkLst.put(key, all);
}
int lid = all.lockLink.attach(TMode.CM_SINGLE, all, 500);
all.lastSent = System.currentTimeMillis();
return lid < 0 ? -lid : 0;
}
/**
* removes an access lock on the server specified.
*
* A client application can obtain an access lock to the given server provided the caller
* has WRITE privileges himself. Once the lock is obtained, no other process will be
* allowed WRITE access regardless of any other access control lists. A lock may be
* preemptive (LOCK_PREEMTIVE) or persistent (LOCK_PERSISTENT). Preemptive locks may be
* aborted (LOCK_ABORT) by other callers with WRITE privileges. Persistent locks may not.
* A client can free a lock he has obtained by calling this method (nominally equivalent to
* setAccessLock() + AccessLockType.LOCK_CANCEL.
* @param context is the targeted context of the server
* @param server is the targeted device server
* @return a tine return code
*
* \b example:
*
* \include eg_AccessLock.java
*/
public static void removeAccessLock(String context, String server)
{
if (context != null && server != null)
{
String key = "/"+context+"/"+server+"/[ACCESSLOCK]";
if (!LockedLnkLst.containsKey(key)) return;
LockedLnkLst.remove(key);
setAccessLock(context,server,AccessLockType.LOCK_UNLOCKED,0);
}
else
{
AccessLockListItem all;
Enumeration<AccessLockListItem> lst = LockedLnkLst.elements();
while (lst.hasMoreElements())
{
all = (AccessLockListItem) lst.nextElement();
setAccessLock(all.lockLink.cntName,all.lockLink.expName,AccessLockType.LOCK_UNLOCKED,0);
}
LockedLnkLst.clear();
}
}
private void checkAccessLockItems()
{
long t = System.currentTimeMillis();
AccessLockListItem all;
Enumeration<AccessLockListItem> lst = LockedLnkLst.elements();
while (lst.hasMoreElements())
{
all = (AccessLockListItem) lst.nextElement();
if (all.lockType != AccessLockType.LOCK_PERSISTENT.ordinal()) continue;
if (all.lockLinkStatus != 0) continue;
if (t < all.lockDuration * 1000 + all.lastSent - 5000) continue;
all.lockLink.attach(TMode.CM_SINGLE, all, 500);
all.lastSent = System.currentTimeMillis();
}
}
public static final int DEFAULT_PROTOCOL_LEVEL = 6;
private static final int RENEWAL_REMINDER = 10;
private static final int RENEWAL_URGENT = 5;
public static final int RETRY_THRESHOLD = 2;
private static final int TIMEOUT_GRACE_INTERVAL = 500;
private static final int BLACKLIST_FLUSH_INTERVAL = 300;
private static TLinkFactory instance = new TLinkFactory();
public static boolean alwaysRetry = true;
public void setAlwaysRetry(boolean value) { alwaysRetry = value; }
public boolean getAlwaysRetry() { return alwaysRetry; }
boolean active;
public boolean terminate;
private TEquipmentModuleFactory gEqmFactory = null;
public TEquipmentModuleFactory getEquipmentModuleFactory()
{
if (gEqmFactory == null) gEqmFactory = TEquipmentModuleFactory.getInstance();
return gEqmFactory;
}
private static boolean autoLinkWatchdogs = true;
private static boolean gIsRunningAsServer = false;
public void SetRunningAsServer(boolean value) { gIsRunningAsServer = value; }
public static boolean isRunningAsServer() { return gIsRunningAsServer; }
private boolean autoLinkErrorAlarms = true;
public void setAutoLinkErrorAlarms(boolean value) { autoLinkErrorAlarms = value; }
public boolean getAutoLinkErrorAlarms() { return autoLinkErrorAlarms; }
public void setAutoLinkWatchdogs(boolean value) { autoLinkWatchdogs = value; }
public boolean getAutoLinkWatchdogs() { return autoLinkWatchdogs; }
Date date = new Date();
int time;
private static String tineUserName = System.getProperty("user.name");
private String doocsUserName = null;
public void setDoocsUserName(String userName)
{
if (userName == null) userName = "";
MsgLog.log("setDoocsUserName","set doocs user to "+userName,0,null,0);
doocsUserName = new String(userName);
}
public String getDoocsUserName() { return doocsUserName; }
/**
* Gets the user name seen in all link requests from this client application.
*
* @return the current user name setting
*/
public String getUserName() { return tineUserName; }
/**
* Sets the user name seen in all link requests to that specified.
*
* @param userName is the desired user name setting
*/
public void setUserName(String userName) { tineUserName = new String(userName); }
private TPacket atp; // general socket for asynchronous communication
private TPacket stp; // socket for synchronous communication
private TPacket qtp; // socket for synchronous queries
private TPacket nmtp; // socket for async net service requests
private TPacket gtp; // globals socket
public TPacket getGlobalsSocket() { return gtp; }
private TPacket amtp; // asynchronous multicast socket
public TPacket getMulticastSocket() { return amtp; }
private static int sckRcvBufferSize;
private static int sckSndBufferSize;
public static int getSckRcvBufferSize() { return sckRcvBufferSize; }
public static void setSckBufferSize(int bufferSize)
{
if (bufferSize > 0x1000) sckRcvBufferSize = bufferSize;
}
public static int getSckSndBufferSize() { return sckSndBufferSize; }
public static void setSckSndBufferSize(int bufferSize)
{
if (bufferSize > 0x1000) sckSndBufferSize = bufferSize;
}
private static int sckTimeToLive;
public static int getSckTimeToLive() { return sckTimeToLive; }
public static void setTimeToLive(int timeToLive)
{
if (timeToLive > 1) sckTimeToLive = timeToLive;
}
TPHdr pHdr; // producer-header for incoming link entries
TGlobalsHdr glbHdr;
public static int debugLevel;
private int totalLinkTimeouts = 0;
private int totalConnectionArrivals = 0;
private boolean useConnectedSockets = false;
public boolean isUseConnectedSockets()
{
return useConnectedSockets;
}
public void setUseConnectedSockets(boolean useConnectedSockets)
{
this.useConnectedSockets = useConnectedSockets;
}
public int getTotalLinkTimeouts() { return totalLinkTimeouts; }
public int getTotalConnectionArrivals() { return totalConnectionArrivals; }
static private int numberTLinksInTable = 1; // assume the ENS is there ...
public int getNumberTLinksInTable() { return numberTLinksInTable;}
// is this significantly quicker to have a static link table rather than a linked list ?
// probably not => TODO: convert this to a linked list
static private int maximumNumberTLinks = 1024;
static private int HEARTBEAT = 60000; // inactive seconds allowed for REFRESH links
static public int getMaximumNumberOfLinks()
{
return maximumNumberTLinks;
}
static public int setMaximumNumberOfLinks(int numberOfLinks)
{
if (numberOfLinks > 10) maximumNumberTLinks = numberOfLinks;
linkTable = Arrays.copyOf(linkTable, maximumNumberTLinks);
return maximumNumberTLinks;
}
private TLinkHook tLinkHook = null;
public void setTLinkHook(TLinkHook hook) { tLinkHook = hook; }
public TLinkHook getTLinkHook() { return tLinkHook; }
private static final TLink tNullLink = new TLink();
protected static LinkedList<TLink> siblings = new LinkedList<TLink>(); // used by common ENS links
protected static TLink[] linkTable = new TLink[maximumNumberTLinks];
public TLink[] getLinkTable()
{
return linkTable;
}
public TLink getLinkFromTable(int linkId)
{
try
{
return linkTable[linkId];
}
catch (Exception any)
{
return null;
}
}
public static void dbgPrint(String msg)
{
if (gIsRunningAsServer)
{
TEquipmentModuleFactory.dbgPrint(msg);
return;
}
if (msg == null) msg = "";
System.out.println(msg);
}
public static void dumpStats()
{
if (gIsRunningAsServer)
{
TEquipmentModuleFactory.dumpStats();
}
else
{
dbgPrint("not running as a server!");
}
}
public static void dumpUserLists()
{
if (gIsRunningAsServer)
{
TEquipmentModuleFactory.dumpUserLists();
}
else
{
dbgPrint("not running as a server!");
}
}
public static void dumpNetsLists()
{
if (gIsRunningAsServer)
{
TEquipmentModuleFactory.dumpNetsLists();
}
else
{
dbgPrint("not running as a server!");
}
}
public static void dumpProperties(String eqmName)
{
if (gIsRunningAsServer)
{
TEquipmentModuleFactory.dumpProperties(eqmName);
}
else
{
dbgPrint("not running as a server!");
}
}
public static void dumpDevices(String eqmName)
{
if (gIsRunningAsServer)
{
TEquipmentModuleFactory.dumpDevices(eqmName);
}
else
{
dbgPrint("not running as a server!");
}
}
public static void dumpDeadbands(String eqmName)
{
if (gIsRunningAsServer)
{
TEquipmentModuleFactory.dumpDeadbands(eqmName);
}
else
{
dbgPrint("not running as a server!");
}
}
public static void dumpSettings()
{
dbgPrint("\nCurrent System Settings");
TInitializer ti = TInitializerFactory.getInstance().getInitializer();
dbgPrint("JVM Settings :");
dbgPrint("JVM max heap size : "+Runtime.getRuntime().maxMemory());
dbgPrint("JVM cur. heap size : "+Runtime.getRuntime().totalMemory());
dbgPrint("JVM cur. free memory : "+Runtime.getRuntime().freeMemory());
if (gIsRunningAsServer)
{
dbgPrint("Server Settings :");
dbgPrint("System Cycle interval: 10 msec");
dbgPrint("Min Polling interval : "+TEquipmentModuleFactory.getMinimumPollingInterval()+" msec");
dbgPrint("Req ack. on change : "+(TEquipmentModuleFactory.gRequireAcknowledgments ? "yes" : "no"));
dbgPrint("Retard cont. removal : "+(TEquipmentModuleFactory.gRetardSingleContractRemoval ? "yes" : "no"));
dbgPrint("Server Burst Limit : "+TEquipmentModuleFactory.getBurstLimit()+" packets");
dbgPrint("Contract renewal len : "+TEquipmentModuleFactory.getRenewalLength()+" items");
dbgPrint("Burst Cycle Delay : "+TEquipmentModuleFactory.getCycleDelay()+" msec");
dbgPrint("Server Packet MTU : "+ti.getSrvPacketMtu()+" bytes");
dbgPrint("Server Recv Buffers : "+ti.getSrvRcvBufferSize()+" bytes");
}
dbgPrint("Client Settings :");
dbgPrint("Connect. tbl capacity: "+maximumNumberTLinks+" items");
dbgPrint("Globals tbl capacity: "+maximumNumberGlobals+" items");
dbgPrint("Client Recv Buffers : "+ti.getClnRcvBufferSize()+" bytes");
dbgPrint("use watchdog links : "+(autoLinkWatchdogs ? "yes" : "no"));
dbgPrint("retry on timeout : "+(alwaysRetry ? "yes" : "no"));
}
public static void dumpContractTable()
{
if (gIsRunningAsServer)
{
TEquipmentModuleFactory.dumpContractTable();
}
else
{
dbgPrint("Not running as server !");
}
}
public static void dumpClientTable()
{
if (gIsRunningAsServer)
{
TEquipmentModuleFactory.dumpClientTable();
}
else
{
dbgPrint("Not running as server !");
}
}
public static void dumpGlobals()
{
TLink glb;
String gs;
InetAddress ia;
TSrvEntry tse;
TFecEntry tfe;
dbgPrint("\nCurrent Globals Table");
for (int i=0; i<numberTLinksInTable; i++)
{
if ((glb=linkTable[i]) == null) continue;
if (glb.sub.mode != TMode.CM_GLOBAL) continue;
gs = glb.toString();
if (glb.dOutput != null)
{
glb.dOutput.setArrayDelimiter(" ");
gs += "((value : "+glb.dOutput.toString()+")";
}
dbgPrint(gs);
tse = glb.srvAddr;
tfe = tse != null ? tse.fecAddr : null;
ia = tfe != null ? tfe.fecHost : null;
gs = " multicast source: "+(tse != null ? glb.getFullDeviceName()+" [FEC: "+ tse.getFecName()+"]" : "unknown");
if (ia != null) gs += " "+ia.getHostAddress();
dbgPrint(gs);
ia = glb.getMulticastGroup();
gs = " multicast group: "+(ia != null ? ia.getHostAddress() : "unknown");
dbgPrint(gs);
gs = " last update: "+ (glb.sub != null ? TDataTime.toString(glb.dOutput.getDataTimeStamp()) : "unknown");
dbgPrint(gs);
}
dbgPrint("");
}
public static void dumpLinkEntry(int i)
{
if (i < 0 || i >= numberTLinksInTable)
{
dbgPrint("link "+i+" is not a link table entry!");
return;
}
if (linkTable[i] == null || linkTable[i] == tNullLink)
{
dbgPrint("link "+i+" is no longer available!");
return;
}
TLink lnk = linkTable[i];
dbgPrint("link ["+i+"]: "+lnk.toString());
dbgPrint("\tdata input: "+(lnk.dInput == null ? "(null)" : lnk.dInput.getObjectInfo()));
dbgPrint("\tdata output: "+(lnk.dOutput == null ? "(null)" : lnk.dOutput.getObjectInfo()));
dbgPrint("\tdata access: "+TAccess.toString(lnk.devAccess));
dbgPrint("\ttransport mode:"+ (lnk.sub == null ? "(null)" : TMode.toString(lnk.sub.mode)));
dbgPrint("\tis active: "+lnk.isActive());
dbgPrint("\tis parent: "+lnk.hasDependencies());
dbgPrint("\tis bound: "+lnk.isBound());
dbgPrint("\tis mca element: "+(lnk.getMcaIndex() > 0));
dbgPrint("\tis mca parent: "+lnk.isMcaParent());
dbgPrint("\tis redirected: "+lnk.isRedirected);
dbgPrint("\tis wildcard link: "+lnk.isWildcardLink);
dbgPrint("\tis grouped: "+lnk.isGrouped());
dbgPrint("\thas notified once: "+lnk.hasNotifiedOnce);
dbgPrint("\thas obtained status: "+lnk.hasObtainedStatus);
dbgPrint("\tlast notification: "+TDataTime.toString(lnk.lastLinkNotification)+"; utc: "+lnk.lastLinkNotification);
dbgPrint("\tlast suppressed notification: "+TDataTime.toString(lnk.lastLinkSuppressedNotification)+"; utc: "+lnk.lastLinkSuppressedNotification);
}
public static void dumpLinkTable()
{
dbgPrint("\nCurrent Connection Table");
String linkItemString;
for (int i=0; i<numberTLinksInTable; i++)
{
if (linkTable[i] == null || linkTable[i] == tNullLink) continue;
linkItemString = "["+i+"] "+linkTable[i].toString();
if (linkTable[i].dOutput != null)
{
if (linkTable[i].dOutput.dCompletionLength == 1)
{
linkTable[i].dOutput.setArrayDelimiter(" ");
linkItemString += "((value : "+linkTable[i].dOutput.toString()+")";
}
else
{
linkItemString += "("+linkTable[i].dOutput.dCompletionLength+" values read)";
}
}
dbgPrint(linkItemString);
}
dbgPrint("");
}
public static void dumpLinkAddresses()
{
dbgPrint("\nConnection Table Active Addresses");
String as;
InetAddress ia;
TSrvEntry tse;
TFecEntry tfe;
for (int i=0; i<numberTLinksInTable; i++)
{
if (linkTable[i] == null || linkTable[i] == tNullLink) continue;
if (!linkTable[i].active) continue;
as = "["+i+"] "+linkTable[i].getFullDeviceNameAndProperty();
tse = linkTable[i].srvAddr;
tfe = tse != null ? tse.fecAddr : null;
ia = tfe != null ? tfe.fecHost : null;
as += " : "+(tse != null ? tse.getEqmName()+"@"+ tse.getFecName()+"]" : "unknown");
dbgPrint(as);
if (ia != null)
{
as = " host: "+ia.getHostAddress();
dbgPrint(as);
as = " port offset: "+tfe.fecPortOffset;
dbgPrint(as);
}
if ((ia=linkTable[i].getMulticastGroup()) != null)
{
as = " multicast group: "+ia.getHostAddress();
dbgPrint(as);
}
if (tfe != null)
{
as = " protocol: "+tfe.getTineProtocol();
dbgPrint(as);
}
if (linkTable[i].sub != null)
{
as = " mode: "+TMode.toString(linkTable[i].sub.mode);
dbgPrint(as);
as = " last update: "+TDataTime.toString(linkTable[i].sub.linkLastTime);
dbgPrint(as);
}
if (linkTable[i].linkStatus != 0)
{
as = " status: " +linkTable[i].getLastError();
dbgPrint(as);
}
}
dbgPrint("");
}
public static void dumpModules()
{
if (gIsRunningAsServer)
{
TEquipmentModuleFactory.dumpModules();
}
else
{
dbgPrint("Not running as server !");
}
}
public int getLinkTableId(TLink lnk)
{
for (int i=0; i<numberTLinksInTable; i++)
{
if (linkTable[i] == lnk) return i;
}
return -1;
}
public static final boolean isEnsCall(String context,String server)
{
if (server == null) return false;
boolean ctxOk = false;
if (context == null || context.length() == 0)
{
ctxOk = true;
}
else
{
if (context.compareTo("DEFAULT") == 0 ||
context.compareToIgnoreCase("SITE") == 0 ||
context.compareToIgnoreCase("SERVICE") == 0)
{
ctxOk = true;
}
}
if (!ctxOk) return false;
if (server.equalsIgnoreCase("ENS")) return true;
if (server.startsWith("ENS#")) return true;
return false;
}
public static final int adjustLinkTableRemove = 0;
public static final int adjustLinkTableAdd = 1;
public static final int adjustLinkTableReplace = 2;
private static Object lnkTblObject = new Object();
public static int adjustLinkTable(TLink lnk,int direction)
{ synchronized(lnkTblObject) {
int i;
if (lnk == null) return -TErrorList.argument_list_error;
switch (direction)
{
case adjustLinkTableRemove:
if (lnk == null || (i = lnk.linkId) < 0) return -TErrorList.argument_list_error;
if (i == 0) return 0; // never remove the ENS link
if (linkTable[i] == null) return 0;
if (debugLevel > 1) DbgLog.log("adjustLinkTable","removing link " + linkTable[i]);
linkTable[i].terminate = false;
linkTable[i] = null;
while (numberTLinksInTable > 1 && linkTable[numberTLinksInTable-1] == null)
{
if (debugLevel > 1) DbgLog.log("adjustLinkTable","decrement number of entries in link table");
numberTLinksInTable--;
}
if (lnk.twcl != null && lnk.twcl.parent != null)
{ // if part of a wildcard link, signal the watchdog to get rid of the parent
lnk.twcl.parent.terminate = true;
}
break;
case adjustLinkTableAdd:
String srv = lnk.getDeviceServer();
String ctx = lnk.getContext();
if (isEnsCall(ctx, srv))
{
if (numberTLinksInTable == 0)
{
if (debugLevel > 1) DbgLog.log("adjustLinkTable","add ENS entry to link table");
numberTLinksInTable++;
}
return 0;
}
int freeslot = 0;
for (i = 1; i < numberTLinksInTable && (linkTable[i] != lnk || linkTable[i] == tNullLink); i++)
{
if (freeslot == 0 && linkTable[i] == null) freeslot = i;
}
if (i < numberTLinksInTable)
{
linkTable[i].terminate = false;
return i; // already in table
}
if (freeslot > 0)
{
linkTable[freeslot] = lnk;
lnk.linkId = freeslot;
return freeslot;
}
if (numberTLinksInTable == maximumNumberTLinks)
{
if (gIsRunningAsServer)
{
TFecLog.log("link "+lnk.getFullDeviceNameAndProperty()+" cannot be added to link table");
TFecLog.log("link table capacity "+TLinkFactory.maximumNumberTLinks+" has been saturated");
}
return -TErrorList.resources_exhausted;
}
if (debugLevel > 1) DbgLog.log("adjustLinkTable","increment number of entries in link table");
lnk.linkId = i;
linkTable[i] = lnk;
numberTLinksInTable++;
return i;
case adjustLinkTableReplace:
if (lnk == null || (i = lnk.linkId) < 0) return -TErrorList.argument_list_error;
if (i == 0) return 0; // never replace the ENS link
if (debugLevel > 1) DbgLog.log("adjustLinkTable","replace link " + linkTable[i]);
linkTable[i] = lnk;
break;
default:
break;
}
return 0;
} }
public int getNumberActiveLinks()
{
int n = 0;
for (int i=1; i<numberTLinksInTable; i++)
if (linkTable[i] != null && linkTable[i].isActive()) n++;
return n;
}
public TLink[] getActiveLinks()
{
int n = 0;
for (int i=1; i<numberTLinksInTable; i++)
if (linkTable[i] != null && linkTable[i].isActive()) n++;
if (n == 0) return null;
TLink[] tbl = new TLink[n];
n = 0;
for (int i=1; i<numberTLinksInTable; i++)
{
if (linkTable[i] != null && linkTable[i].isActive())
tbl[n++] = linkTable[i];
if (n >= tbl.length) break;
}
return tbl;
}
boolean hasDeferredLinks = false;
public boolean hasDeferredLinks()
{
if (hasDeferredLinks) return true;
for (int i = 0; i < numberTLinksInTable; i++)
{
if (linkTable[i] != null && linkTable[i] != tNullLink)
{
if (linkTable[i].delayEstablishLink) return true;
}
}
hasDeferredLinks(false);
return false;
}
public void hasDeferredLinks(boolean value) { hasDeferredLinks = value; }
boolean isInsideCallback = false;
private LinkedList<TWildcardLink> wcList = null;
// java 1.5 or higher !!!! ->
private Hashtable<String,TWatchdogLink> wdList = null;
public boolean hasWatchdogLink(String key)
{
if (wdList == null) return false;
return wdList.contains(key.toUpperCase());
}
public TWatchdogLink getWatchdogLink(String key)
{
if (wdList == null) return null;
return wdList.get(key.toUpperCase());
}
public void addWatchdogLink(String key,TWatchdogLink lnk)
{
if (wdList == null) wdList = new Hashtable<String, TWatchdogLink>();
if (key != null && lnk != null) wdList.put(key.toUpperCase(), lnk);
}
public void rmvWatchdogLink(String key)
{
if (wdList == null) wdList = new Hashtable<String, TWatchdogLink>();
if (key != null) wdList.remove(key.toUpperCase());
}
private static Hashtable<Object,TLinkGroup> grpList = null;
public TLinkGroup getGroup(TLinkCallback cb)
{
TLinkGroup grp = null;
if (cb == null) return null;
if (grpList == null) grpList = new Hashtable<Object,TLinkGroup>();
if (grpList.containsKey(cb)) return (TLinkGroup)grpList.get(cb);
if (debugLevel > 0) DbgLog.log("getGroup","adding new group to group table");
grp = new TLinkGroup();
grpList.put(cb,grp);
return grp;
}
public TLinkGroup getGroup(TCallback cb)
{
TLinkGroup grp = null;
if (cb == null) return null;
if (grpList == null) grpList = new Hashtable<Object,TLinkGroup>();
if (grpList.containsKey(cb)) return (TLinkGroup)grpList.get(cb);
grp = new TLinkGroup();
grpList.put(cb,grp);
return grp;
}
public static void dumpGroups()
{
if (grpList == null || grpList.size() == 0)
{
dbgPrint("no link groups active");
return;
}
TLinkGroup grp = null;
Iterator<TLinkGroup> itr = grpList.values().iterator();
while (itr.hasNext())
{
grp = itr.next();
dbgPrint("\n *** link group "+grp.getGroupHead().getFullDeviceNameAndProperty()+" contains : ***");
dbgPrint(grp.toString());
}
}
public static void resetGroups()
{
if (grpList == null || grpList.size() == 0)
{
dbgPrint("no link groups to reset!");
return;
}
TLinkGroup grp = null;
Iterator<TLinkGroup> itr = grpList.values().iterator();
while (itr.hasNext())
{
grp = itr.next();
dbgPrint("reset link group "+grp.getGroupHead().getFullDeviceNameAndProperty());
grp.reset();
}
}
public TWildcardLink getWildcardLink()
{
TWildcardLink wc = null;
if (wcList != null)
{
for (int i=0; i<wcList.size(); i++)
{
wc = (TWildcardLink)wcList.get(i);
if (wc.parent == null) return wc;
}
}
else
{
wcList = new LinkedList<TWildcardLink>();
}
wc = new TWildcardLink();
wcList.add(wc);
return wc;
}
public int getWildcardLinkId(TWildcardLink wc)
{
if (wc == null || wcList == null) return -1;
for (int i=0; i<wcList.size(); i++)
{
if ((TWildcardLink)wcList.get(i) == wc) return i;
}
return -1;
}
public void rmvWildcardLink(TWildcardLink wc)
{
if (wc == null || wcList == null) return;
for (int i=0; i<wcList.size(); i++)
{
if ((TWildcardLink)wcList.get(i) == wc)
{
wc.links = null;
wc.list = null;
wc.status = null;
wc.parent = null;
wc.tcb = null;
wc.tlcb = null;
}
}
}
private TFactoryThread atfThrd;
public TFactoryThread getAsynchronousLinkThread() { return atfThrd; }
private TFactoryThread stfThrd;
public TFactoryThread getSynchronousLinkThread() { return stfThrd; }
private TFactoryThread qtfThrd;
public TFactoryThread getQueryLinkThread() { return qtfThrd; }
private TFactoryGlobalsThread gtfThrd;
public TFactoryGlobalsThread getGlobalsLinkThread() { return gtfThrd; }
private TFactoryThread mtfThrd;
public TFactoryThread getMulticastLinkThread() { return mtfThrd; }
private TFactoryThread ntfThrd;
public TFactoryThread getNetcastLinkThread() { return ntfThrd; }
final TFactoryWatchdogThread tfwdThrd = new TFactoryWatchdogThread();
public static synchronized void watchdogCycle()
{
if (instance != null &&
instance.tfwdThrd.isWaiting())
{ // in a wait state, but we need it now !
instance.tfwdThrd.interrupt();
}
}
//static final int maximumNumberTBuckets = 10;
static final int maximumNumberGlobals = 25;
private LinkedList<TLinkBucket> bucketList = new LinkedList<TLinkBucket>();
//private TLinkBucket[] bucketTable = new TLinkBucket[maximumNumberTBuckets];
private TInitializer initializer = TInitializerFactory.getInstance().getInitializer();
public TInitializer getInitializer()
{
return initializer;
}
public void startGlobalsListener()
{
if (gtp == null)
{ // socket not yet created
gtp = new TPacket(initializer.getGCastPort());
}
if (gtfThrd == null)
{
gtfThrd = new TFactoryGlobalsThread(gtp);
gtfThrd.start();
}
}
public void startMulticastListener(int rcvBufferSize,int timeToLive)
{
if (amtp == null)
{ // socket not yet created
amtp = new TPacket(initializer.getMCastPort(),rcvBufferSize,timeToLive);
}
if (mtfThrd == null)
{
mtfThrd = new TFactoryThread(amtp,"async mcast",true);
mtfThrd.start();
}
}
public class TLinkBucket extends TBucket
{
private int transport = TTransport.TCP;
private int buffersize = TPacket.MAX_DATAGRAM_SIZE;
private int port;
public TLinkBucket(TLink lnk) // index in link table
{
int index = lnk.linkId;
if (index < 0 || index >= TLinkFactory.getMaximumNumberOfLinks()) return;
if (linkTable[index].getBucket() != null) return; // already have a bucket
TBucketThread tfBckThrd = getTBucketThread(index);
if (tfBckThrd != null)
{ // a thread is already attached to this link
TLinkBucket tb = tfBckThrd.getBucket();
setSocket(tb.getSocket());
setOutputStream(tb.getOutputStream());
setInputStream(tb.getInputStream());
return;
}
// this is a new one ...
if (TMode.isStream(lnk.sub.mode))
{
transport = TTransport.STREAM;
buffersize = lnk.dOutput.getDataSize();
if (buffersize < TPacket.MAX_DATAGRAM_SIZE) buffersize = TPacket.MAX_DATAGRAM_SIZE;
port = getInitializer().getStreamPort();
}
else
{
port = getInitializer().getTCPPort();
}
port += linkTable[index].srvAddr.fecAddr.fecPortOffset;
if (initBucket(linkTable[index].srvAddr.fecAddr.fecHost,port,
new TBucketThread(this,transport),buffersize) == 0)
{
putTLinkBucket(this);
activate();
}
}
public int getActiveLinks()
{
int n = 0;
for (int i=0; i<numberTLinksInTable; i++)
{
if (linkTable[i] == null) continue;
if (!linkTable[i].active) continue;
if (linkTable[i].tb != this) continue;
n++;
}
return n;
}
public int getTransport()
{
return transport;
}
}
public class TBucketThread extends Thread
{
TLinkBucket tb;
protected boolean isWaiting = false;
protected int transport = TTransport.TCP;
private byte[] payload = new byte[TPacket.MAX_DATAGRAM_SIZE];
public TLinkBucket getBucket() { return tb; }
private Socket sck = null;
public TBucketThread(TLinkBucket tBucket,int type)
{
tb = tBucket;
if ((type & (TTransport.STREAM|TTransport.TCP)) == 0) type = TTransport.TCP;
transport = type;
tb.active = true;
String s = null;
sck = tb.getSocket();
if (sck != null) s = new String("tcp port " + sck.getLocalPort());
else s = new String("tcp unbound socket ?");
this.setName("Link Factory " + s);
}
public synchronized void run()
{
byte[] msgsizb = new byte[4];
int nread, nleft, n, payloadptr, payloadsize, sizeptr=0;
MsgLog.log("TBucketThread","Link Factory Thread " + getName() + " started ...",0,null,1);
try
{
InputStream is = tb.getInputStream();
while (tb.active)
{
if (terminate) break;
if (debugLevel > 2) DbgLog.log("TBucketThread","Waiting for steam data ...");
isWaiting = true;
if ((nread = is.read(payload, 0, TPacket.MAX_DATAGRAM_SIZE)) == -1)
{
tb.isDeactivating = true;
MsgLog.log("TBucketThread","read stream at EOF -> close socket !",0,null,0);
break;
}
tb.touch();
totalConnectionArrivals++;
nleft = nread;
payloadptr = 0;
while (nleft > 0)
{
if (tb.getBucketPointer() == 0)
{ // at the beginning
if (transport == TTransport.STREAM)
{
int count = nleft < 4 ? nleft : 4 - sizeptr;
System.arraycopy(payload, payloadptr, msgsizb, sizeptr, count);
sizeptr += count;
if (sizeptr >= 4)
{// reset
sizeptr = 0;
}
else
{ // only a couple of bytes have dribbled in ...
break;
}
payloadsize = Swap.Long(new DataInputStream(new ByteArrayInputStream(msgsizb)).readInt());
if (payloadsize > tb.getCapacity())
{
tb.setCapacity(payloadsize+TPacket.MAX_DATAGRAM_SIZE);
}
}
else
{
int count = nleft < 2 ? nleft : 2 - sizeptr;
System.arraycopy(payload, payloadptr, msgsizb, sizeptr, count);
sizeptr += count;
if (sizeptr >= 2)
{// reset
sizeptr = 0;
}
else
{ // only a couple of bytes have dribbled in ...
break;
}
//System.arraycopy(payload, payloadptr, msgsizb, 0, 2);
payloadsize = Swap.Short(new DataInputStream(new ByteArrayInputStream(msgsizb)).readShort());
}
tb.setBucketSize(payloadsize); // set bucket size for this payload
}
int ptr = tb.getBucketPointer();
int siz = tb.getBucketSize();
byte[] buf = tb.getBucketBuffer();
n = siz - ptr; // remaining bucket buffer space
if (n < 0 || payloadptr < 0 || ptr < 0)
{
MsgLog.log("TBucketThread", "invalid copy parameters: payload ptr "+payloadptr+", bucket pointer "+ptr+", length "+n,TErrorList.tcp_socket_error,null,1);
ptr = 0;
nleft = 0;
}
else if (nleft >= n) // at least enough
{ // and we've filled up the bucket !
if (ptr + n > buf.length)
{ // this shouldn't happen, but it seems to ?
MsgLog.log("TBucketThread", "copy "+n+" bytes at "+ptr+" would overflow buffer of "+buf.length+" bytes",TErrorList.tcp_socket_error,null,1);
nleft = n = buf.length - ptr;
}
if (payloadptr + n > payload.length)
{ // this shouldn't happen, but it seems to ?
MsgLog.log("TBucketThread", "copy "+n+" bytes from "+payloadptr+" is past buffer length of "+payload.length+" bytes",TErrorList.tcp_socket_error,null,1);
nleft = n = payload.length - payloadptr;
}
System.arraycopy(payload, payloadptr, buf, ptr, n);
InterpretIncomingData(transport,buf, siz, tb.getBucketEndpoint(), tb.getBucketPort(), false);
payloadptr += n; // move the read buffer pointer along
nleft -= n; // decrement what's remaining to be read
ptr = 0; // reset the bucket pointer
}
else
{
System.arraycopy(payload, payloadptr, buf, ptr, nleft);
ptr += nleft;
nleft = 0; // and we're out of the loop !
}
tb.setBucketPointer(ptr);
if (payloadptr >= TPacket.MAX_DATAGRAM_SIZE && nleft != 0)
{ // should not be possible, but it's happened !
MsgLog.log("TBucketThread","payload pointer "+payloadptr+" past end; last set: "+n+" bytes",TErrorList.code_failure,null,0);
ptr = 0;
nleft = 0;
}
}
}
tb.getSocket().close();
}
catch (IOException e)
{ // most likely an IOException ...
if (sck != null && !sck.isClosed())
MsgLog.log("TBucketThread", e.toString(), TErrorList.io_error, e, 1);
}
catch (Exception e)
{
e.printStackTrace();
MsgLog.log("TBucketThread", e.toString(), TErrorList.code_failure, e, 0);
}
finally
{
removeTLinkBucket(tb,false);
}
}
}
public TBucketThread getTBucketThread(int index)
{
if (index < 0 || index >= numberTLinksInTable) return null;
TFecEntry fec = linkTable[index].srvAddr.fecAddr;
TLinkBucket tlb;
synchronized (bucketList)
{
Iterator<TLinkBucket> it = bucketList.iterator();
while (it.hasNext())
{
tlb = it.next();
if (tlb.getTransport() == TTransport.TCP &&
tlb.getBucketPort() != initializer.getTCPPort()+fec.fecPortOffset)
continue;
if (tlb.getTransport() == TTransport.STREAM &&
tlb.getBucketPort() != initializer.getStreamPort()+fec.fecPortOffset)
continue;
if (tlb.getBucketEndpoint() != fec.fecHost) continue;
return (TBucketThread)tlb.getBucketThread();
}
}
return null;
}
public int putTLinkBucket(TLinkBucket tb)
{
synchronized (bucketList)
{
bucketList.add(tb);
}
return 0;
}
private void removeIdleTLinkBuckets(long timeStamp)
{
synchronized (bucketList)
{
Iterator<TLinkBucket> tlbitr = bucketList.iterator();
TLinkBucket tlb;
Socket sck;
try
{
while (tlbitr.hasNext())
{
tlb = tlbitr.next();
if (tlb.getActiveLinks() == 0 &&
timeStamp > tlb.getTimeLastActive() + TBucket.ALLOWED_IDLE_TIME)
{
tlb.setBucketPort(0);
sck = tlb.getSocket();
tlb.isDeactivating = false;
tlbitr.remove();
sck.shutdownInput();
sck.shutdownOutput();
sck.close();
MsgLog.log("removeIdleTLinkBuckets", "remove idle tcp connection to "+tlb.getBucketEndpoint().getHostAddress(),0,null,1);
}
}
}
catch (IOException e)
{
MsgLog.log("removeIdleTLinkBuckets"," IOException : " + e.toString(),TErrorList.io_error,e,1);
}
catch (Exception e)
{
e.printStackTrace();
MsgLog.log("removeIdleTLinkBuckets",e.toString(),TErrorList.code_failure,e,1);
}
}
}
private int removeTLinkBucket(TLinkBucket tb,boolean removeLinks)
{
if (tb == null) return -1;
for (int i = 0; i < numberTLinksInTable; i++)
{
if (linkTable[i] == null || linkTable[i].tb != tb) continue;
linkTable[i].tb = null;
if (removeLinks)
{
linkTable[i].active = false;
linkTable[i].terminate = true;
}
}
tb.setBucketPort(0);
synchronized (bucketList)
{
bucketList.remove(tb);
}
try
{
Socket sck = tb.getSocket();
if (sck != null && !sck.isClosed())
{
sck.shutdownInput();
sck.shutdownOutput();
sck.close();
}
}
catch (IOException e)
{
MsgLog.log("removeBucketThread"," IOException : " + e.toString(),TErrorList.io_error,e,1);
}
catch (Exception e)
{
e.printStackTrace();
MsgLog.log("removeBucketThread",e.toString(),TErrorList.code_failure,e,1);
}
finally
{
tb.isDeactivating = false;
}
return 0;
}
public class TLinkFactoryShutdown extends Thread
{
public synchronized void run()
{
DbgLog.log("TLinkFactoryShutdown","shutting down link factory");
this.setName("Link Factory shutdown");
for (int i = 0; i < numberTLinksInTable; i++)
{
if (linkTable[i] != null && linkTable[i] != tNullLink)
{
linkTable[i].close();
}
}
}
}
public class TFactoryWatchdogThread extends Thread
{
private boolean isWaiting = false;
public boolean isWaiting() { return isWaiting; }
private ArrayList<TLink> deferredLinks = new ArrayList<TLink>();
private TFecEntry deferredTarget = null;
private void checkLink(TLink lnk,long ltime)
{
long deltatime, gracePeriod, tcpIdlePeriod;
time = (int) (ltime / 1000); // time in seconds
int syncLinkTimeouts = 0;
int to_ceiling;
boolean linkHasStatus = false;
boolean suppressNotify = false;
boolean isGlobalLink = false;
boolean mcgShuffle = false;
boolean linkRemovalAllowed = false;
boolean trace = TLinkFactory.traceKey != null && lnk.isTraceLink();
try
{
if (lnk.delayEstablishLink)
{
if (trace) lnk.traceLink("checkLink", "collect delayed link establishment");
lnk.delayEstablishLink = false;
if (lnk.canSendPacked())
{
if (deferredTarget == null) deferredTarget = lnk.srvAddr.fecAddr;
if (deferredTarget != lnk.srvAddr.fecAddr)
{ // oops! going to a different FEC, wait another round ...
lnk.delayEstablishLink(true);
if (trace) lnk.traceLink("checkLink", "wrong target server -> continue delay");
return;
}
lnk.needsToSendLinkRequest = true;
deferredLinks.add(lnk);
}
else
{
if (trace) lnk.traceLink("checkLink", "prepare to send link renewal request");
int sts = lnk.linkStatus;
if (lnk.isRenewal()) lnk.hasRenewed = true;
sendLinkRequest(lnk);
lnk.setIsRenewal(false);
lnk.linkStatus = sts;
}
return;
}
if (lnk.needsToStartLinkWatchdog)
{ // constructor will add itself to the factory hash table
lnk.needsToStartLinkWatchdog = false;
new TWatchdogLink(lnk);
}
linkRemovalAllowed = (lnk.sub != null && lnk.sub.starttime < time && (lnk.sub.linkLastTime/1000) < time);
if (lnk.terminate == true && lnk.linkId > 0 && linkRemovalAllowed)
{ // marked for termination and removal
if (trace) lnk.traceLink("checkLink", "remove terminated link");
if (debugLevel > 1)
{
DbgLog.log("TFactoryWatchdogThread","remove terminated link " + lnk.linkId + " /" + lnk.cntName + "/"
+ lnk.expName + "/" + lnk.devName + " " + lnk.devProperty);
}
synchronized (lnk)
{ // wake up the calling thread
lnk.notifyAll();
}
removeTLink(lnk);
}
if (lnk.removedFromMcaList > 0)
{ // wait a good 5 seconds before actually removing an MCA parent
if (time > lnk.removedFromMcaList + 4) synchronized (mcaLst)
{ // re-check the removal flag ...
if (lnk.removedFromMcaList > 0)
{
if (trace) lnk.traceLink("checkLink", "remove terminated MCA parent");
unlinkMcaParent(lnk);
}
}
}
if (lnk.linkStatus != TErrorList.property_is_mca &&
lnk.getMcaIndex() > 0)
{ // don't check the mca links (unless a cancel is needed)
if (!lnk.active)
{
if (trace) lnk.traceLink("checkLink", "close inactive MCA element link");
lnk.close();
}
return;
}
if (!lnk.active)
{
if (trace) lnk.traceLink("checkLink", "link is not active");
return;
}
if (lnk.sub == null)
{
if (trace) lnk.traceLink("checkLink", "link subscription is null !");
return; // what's the point ?
}
if (lnk.linkStatus == TErrorList.has_bitfield_tag &&
lnk.mapSingleFieldToBitfield() != 0) return;
if (lnk.linkStatus == TErrorList.has_structure_tag &&
lnk.mapSingleFieldToStruct() != 0) return;
if (lnk.linkStatus == TErrorList.property_is_mca)
{
lnk.linkStatusSource = TLink.STATUS_LOCAL;
lnk.linkStatus = 0;
if (trace) lnk.traceLink("checkLink", "trap property_is_mca status");
return;
}
if (TErrorList.isCoercive(lnk.linkStatus))
{ // need to re-submit the link
short mod = lnk.sub.mode;
TLink xlnk = getExistingLink(lnk, lnk.dOutput, lnk.dInput);
if (xlnk != null)
{ // join in ...
if (trace) lnk.traceLink("checkLink", "coerced link depends on link "+xlnk.linkId);
linkTable[lnk.linkId] = null;
lnk.bindToParentLink(xlnk,lnk.dOutput,lnk.dInput);
lnk.devAccess = TMode.CM_REGISTER;
//if (lnk.sub != null) lnk.sub.mode = TMode.CM_REGISTER;
if (deferredLinks.contains(lnk)) deferredLinks.remove(lnk);
if (lnk.tlcb == null && lnk.tcb == null) lnk.needsWakeUpCall = true;
if (xlnk.hasObtainedStatus)
{ // then handle this here quickly
lnk.getOutputDataObject().pushBytes(xlnk.getOutputDataObject().getDataBuffer());
lnk.linkStatus = xlnk.linkStatus;
lnk.linkErrString = xlnk.linkErrString;
cannotNotifyFromWatchdogThread = true;
fireCallbackEvent("TLinkFactory.Watchdog", lnk);
cannotNotifyFromWatchdogThread = false;
}
}
else
{
if (trace) lnk.traceLink("checkLink", "resubmitting coerced link "+lnk.linkId);
lnk.con = new TContract(lnk);
lnk.sub = new TSubscription(lnk.con, lnk); // going out ...
lnk.sub.mode = mod;
sendLinkRequest(lnk);
lnk.linkStatus = 0;
lnk.linkStatusSource = TLink.STATUS_LOCAL;
}
return;
}
if (lnk.linkStatus == TErrorList.illegal_protocol)
{ // need to re-submit the link
if (lnk.getTineProtocol() == 6)
{ // legacy server end-point
lnk.setTineProtocol(5);
short mod = lnk.sub.mode;
lnk.sub = new TSubscription(lnk.con, lnk); // going out ...
lnk.sub.mode = mod;
sendLinkRequest(lnk);
lnk.linkStatus = 0;
lnk.linkStatusSource = TLink.STATUS_LOCAL;
lnk.sub.linkLastTime = ltime;
return;
}
lnk.sub.mode = TMode.CM_CANCEL;
MsgLog.log("TFactoryWatchdogThread","link " + lnk.linkId + " protocol level " + lnk.getTineProtocol() + " is invalid",TErrorList.illegal_protocol,null,1);
}
if (lnk.linkStatus == TErrorList.reacquire_address)
{
lnk.lastEnsAddressRequest = ltime;
lnk.srvAddr.getAddressFromENS(lnk.expName, lnk.cntName);
sendLinkRequest(lnk);
return;
}
if (lnk.linkInvalidCount > TO_THRESHOLD*3 &&
lnk.lastEnsAddressRequest < ltime + ENS_BACKOFF_THRESHOLD)
{ // non_existent_elem could imply a 'moved' server !
lnk.lastEnsAddressRequest = ltime;
lnk.linkInvalidCount = 0;
lnk.srvAddr.getAddressFromENS(lnk.expName, lnk.cntName);
}
if (TMode.isStream(lnk.sub.mode)) return; // streams don't timeout here!
// the link is still active ...
linkHasStatus = false;
short baseMode = (short) (lnk.sub.mode & 0x00ff);
tcpIdlePeriod = 3000;
deltatime = ltime - lnk.sub.linkLastTime;
gracePeriod = TIMEOUT_GRACE_INTERVAL; //lnk.devTimeout < 1000 ? 100 : 1000;
if (deltatime > gracePeriod && lnk.isLinkReassignment)
lnk.isLinkReassignment = false;
if (TMode.hasLongDeadband(baseMode) && lnk.isAlive())
gracePeriod += HEARTBEAT;
isGlobalLink = baseMode == TMode.CM_GLOBAL;
to_ceiling = lnk.devTimeout;
if (lnk.isGrouped())
{ // belongs to a group: if synchronized find the best timeout ceiling
TLinkGroup g = lnk.getGroup();
if (g.getUpdateInterval() > 0 &&
g.getSynchronizationLevel() == TLinkGroup.GRP_SYNC_INSYNC)
to_ceiling = lnk.getGroup().getUpdateInterval();
}
if (deltatime > (long) (to_ceiling + gracePeriod) && TMode.canTimeOut(baseMode))
{ // link has timed out ...
if (!lnk.canTimeout)
{ // is inside 'interpretIncomingData'
lnk.sub.linkLastTime = ltime;
if (trace) lnk.traceLink("checkLink", "(inside intrpretIncomingData: suppress timeout link "+lnk.linkId);
return;
}
linkHasStatus = true;
lnk.hasObtainedStatus = true;
if (lnk.linkStatus == -1)
{ // a pending link has not come in within the alloted time
lnk.lastLinkStatus = lnk.linkStatus = TErrorList.link_timeout;
lnk.linkStatusSource = TLink.STATUS_LOCAL;
if (trace) lnk.traceLink("checkLink", "pending link continues to timeout: link "+lnk.linkId);
return;
}
if (lnk.srvAddr.isENSCall(lnk.expName,lnk.cntName) &&
siblings.isEmpty() &&
!lnk.cannotNotifyFromWatchdogThread)
{
TSrvEntry.toggleENS();
lnk.srvAddr.getAddress(lnk.devName,lnk.expName,lnk.cntName);
}
if (autoLinkErrorAlarms && isRunningAsServer() && lnk.canSetAlarms)
{ // set some relevant alarm
if (lnk.isInAlarmState ||
lnk.linkTimeouts > RETRY_THRESHOLD ||
baseMode == TMode.CM_SINGLE)
{
getEquipmentModuleFactory().setFecLinkErrorAlarm(lnk,baseMode);
lnk.isInAlarmState = true;
}
}
totalLinkTimeouts++;
lnk.linkTimeouts++;
suppressNotify = (lnk.retryOnTimeoutError && lnk.linkTimeouts < RETRY_THRESHOLD) ? true : false;
if (debugLevel > 0)
{
DbgLog.log("TFactoryWatchdogThread","link " + lnk.linkId + " link timeout " + lnk.devTimeout
+ " exceeded : " + ltime + " vs " + lnk.sub.linkLastTime + " timeout counter : "
+ lnk.linkTimeouts);
if (suppressNotify)
{
if (trace) lnk.traceLink("checkLink", "suppressing timeout notification: link "+lnk.linkId);
DbgLog.log("TFactoryWatchdogThread","suppressing link timeout notification");
}
}
lnk.notifyPending = false;
mcgShuffle = false;
if (lnk.linkTimeouts > TO_THRESHOLD*3 &&
lnk.lastEnsAddressRequest < ltime + ENS_BACKOFF_THRESHOLD)
{
if (trace) lnk.traceLink("checkLink", "reaquire address for link "+lnk.linkId);
lnk.lastEnsAddressRequest = ltime;
lnk.linkTimeouts = 0; // reset it
lnk.srvAddr.getAddressFromENS(lnk.expName, lnk.cntName);
if (isGlobalLink) mcgShuffle = true;
}
if (lnk.linkStatus != TErrorList.link_blacklisted)
{ // set the link status
lnk.linkStatus = TErrorList.link_not_open;
lnk.linkStatusSource = TLink.STATUS_LOCAL;
}
else
{ // a blacklisted link keeps his status code!
linkHasStatus = false;
}
if (!isGlobalLink)
{ // only do this if this is not a globals link !
synchronized (pHdr) { pHdr.lnkCounter = 0; }
}
if (lnk.isGrouped())
{
if (!lnk.getGroup().canNotify(lnk)) suppressNotify = true;
}
if (lnk.isInsideCallback)
{
if (trace) lnk.traceLink("checkLink", "timed out link is inside callback !"+lnk.linkId);
return;
}
if (!lnk.getCriticalSection()) return;
if (lnk.linkTimeouts > TO_RETRY_THRESHOLD)
{ // is there an error value ?
fillinIncomingDataWithErrValue(lnk);
}
if (!suppressNotify && lnk.isGrouped())
{
lnk.notifyPending = false;
if (!lnk.getGroup().canNotify(lnk))
{
suppressNotify = true;
}
else
{
if (debugLevel > 1)
DbgLog.log("TFactoryWatchdogThread","all members of group have updated");
}
}
// TODO: the logic below looks like it can be cleaned up a bit ...
if (!suppressNotify && lnk.linkStatusLastNotification != lnk.linkStatus)
{
String msg;
if (baseMode > TMode.CM_SINGLE)
msg = "link status changed from "+TErrorList.getErrorString(lnk.linkStatusLastNotification)+" to "+TErrorList.getErrorString(lnk.linkStatus);
else
msg = TErrorList.getErrorString(lnk.linkStatus);
MsgLog.log("TFactoryWatchdogThread",
lnk.getFullDeviceNameAndProperty()+" "+msg,lnk.linkStatus,null,1);
lnk.linkStatusLastNotification = lnk.linkStatus;
}
if (!suppressNotify && baseMode > TMode.CM_SINGLE) synchronized (lnk)
{
lnk.needsNotification = true;
if (lnk.terminate == false)
{
allowSynchronousLinks = false;
fecEntryWithTimeout = lnk.srvAddr.getFecAddr();
cannotNotifyFromWatchdogThread = true;
//fireCallbackEvent("TFactoryWatchdogThread",lnk);
fireCallbackEventCheckDependencies("TFactoryWatchdogThread",lnk);
cannotNotifyFromWatchdogThread = false;
fecEntryWithTimeout = null;
allowSynchronousLinks = true;
lnk.needsNotification = false;
}
lnk.notifyAll(); // wake up the calling thread
lnk.sub.linkLastTime = ltime;
}
lnk.freeCriticalSection();
if (isGlobalLink)
{ // missing globals: try to take corrective action
if (lnk.expName.compareToIgnoreCase("CYCLER") == 0)
{ // don't let missing cyclers report errors in the link table
lnk.linkStatus = 0;
lnk.linkStatusSource = TLink.STATUS_LOCAL;
}
if (lnk.srvAddr == null ||
lnk.srvAddr.fecAddr == null ||
lnk.srvAddr.fecAddr.fecHost == null)
return;
// globals timing out: check the address occasionally
InetAddress mygrp = lnk.getMulticastGroup();
String[] mcaddr = initializer.getGCastAddress().split("\\.");
String[] ipaddr = lnk.srvAddr.fecAddr.fecHost.getHostAddress().split("\\.");
String ip = mcaddr[0] + "." + mcaddr[1] + "." + ipaddr[2] + "." + ipaddr[3];
InetAddress tgtgrp = InetAddress.getByName(ip);
if (mygrp != null && !mygrp.equals(tgtgrp))
{ // new multicast address !
if (debugLevel > 0)
DbgLog.log("TFactoryWatchdogThread",lnk.getFullDeviceNameAndProperty()+" globals multicast group changed from "
+ mygrp.toString()+" to "+tgtgrp.toString()+" "+TDataTime.toString(ltime));
mcgShuffle = true;
}
if (mcgShuffle)
{
detachMulticastGroup(lnk.isGlobalsLink,mygrp);
lnk.setMulticastGroup(null);
if (numLinksInMulticastGroup(tgtgrp) == 0)
{
getGlobalsSocket().getSocket().joinGroup(tgtgrp);
}
lnk.setMulticastGroup(tgtgrp);
}
return;
}
if (baseMode > TMode.CM_SINGLE)
{
lnk.sub.mode |= TMode.CM_RETRY;
lnk.sub.linkLastTime = ltime;
if (trace) lnk.traceLink("checkLink", "resubmit link request for presistent link "+lnk.linkId);
sendLinkRequest(lnk);
}
else if (baseMode == TMode.CM_SINGLE)
{
if (suppressNotify)
{
lnk.sub.mode |= TMode.CM_RETRY;
lnk.sub.linkLastTime = ltime;
if (trace) lnk.traceLink("checkLink", "resubmit link request for single link "+lnk.linkId);
sendLinkRequest(lnk);
}
else if (lnk.getCriticalSection())
{
lnk.needsNotification = true;
synchronized (lnk)
{
if (lnk.terminate == false)
{
allowSynchronousLinks = false;
fecEntryWithTimeout = lnk.srvAddr.getFecAddr();
cannotNotifyFromWatchdogThread = true;
fireCallbackEvent("TFactoryWatchdogThread",lnk);
cannotNotifyFromWatchdogThread = false;
fecEntryWithTimeout = null;
allowSynchronousLinks = true;
lnk.needsNotification = false;
}
if (trace) lnk.traceLink("checkLink", "cancel link "+lnk.linkId);
if (debugLevel > 1)
DbgLog.log("TFactoryWatchdogThread"," cancel single link " + lnk.linkId + " from watchdog" + " "
+ TDataTime.toString(ltime));
if ((lnk.sub.mode & TMode.CM_CONNECT) == TMode.CM_CONNECT)
{
tcpIdlePeriod = 0;
lnk.sub.mode = (short) (TMode.CM_CANCEL | TMode.CM_CONNECT);
}
else
{
lnk.sub.mode = TMode.CM_CANCEL; // turn off the link
}
lnk.active = false; lnk.notifyPending = false;
syncLinkTimeouts++;
if ((lnk.linkTimeouts > TO_THRESHOLD || syncLinkTimeouts > TO_THRESHOLD) &&
lnk.lastEnsAddressRequest < ltime + ENS_BACKOFF_THRESHOLD)
{
lnk.linkTimeouts = 0;
syncLinkTimeouts = 0;
lnk.lastEnsAddressRequest = ltime;
lnk.cannotNotifyFromWatchdogThread = true;
lnk.srvAddr.getAddressFromENS(lnk.expName, lnk.cntName);
lnk.cannotNotifyFromWatchdogThread = false;
if (trace) lnk.traceLink("checkLink", "reacquire address for link "+lnk.linkId);
}
if (lnk.removeOnClose)
{
if (trace) lnk.traceLink("checkLink", "mark link as terminated for link "+lnk.linkId);
if (debugLevel > 1) DbgLog.log("TFactoryWatchdogThread","mark link " + lnk.linkId + " for termination");
lnk.terminate = true; // flush the table next time through
}
lnk.notifyAll(); // wake up the calling thread
}
lnk.freeCriticalSection();
}
}
}
if (deltatime > (long) (lnk.devTimeout + tcpIdlePeriod)
&& lnk.sub.mode == (TMode.CM_CANCEL | TMode.CM_CONNECT)
&& lnk.linkBlacklists == 0 && lnk.tb != null)
{
if (((TLinkBucket)lnk.tb).getActiveLinks() == 0)
removeTLinkBucket((TLinkBucket)lnk.tb,true);
}
if (lnk.sub.mode == TMode.CM_CANCEL && !lnk.active && lnk.linkStatus != -1)
{
if (debugLevel > 1) DbgLog.log("TFactoryWatchdogThread","watchdog ignoring cancelled link " + lnk.linkId);
//lnk.terminate = true;
}
if (debugLevel > 3 || (debugLevel > 2 && linkHasStatus))
{
DbgLog.log("TFactoryWatchdogThread","link : " + "/" + lnk.cntName + "/" + lnk.expName + "/" + lnk.devName
+ " " + lnk.devProperty + " : linkStatus " + lnk.linkStatus + " Link active : "
+ lnk.active + " terminate : " + lnk.terminate + " " + TDataTime.toString(ltime));
}
}
catch (Exception e)
{
e.printStackTrace();
MsgLog.log("TFactoryWatchdogThread", e.toString(), TErrorList.code_failure,e, 1);
}
}
public synchronized void run()
{
this.setName("Link Factory watchdog");
MsgLog.log("TFactoryWatchdogThread","Thread " + getName() + " started ...",0,null,1);
TLink lnk;
long ltime;
ltime = System.currentTimeMillis();
time = (int) (ltime / 1000); // time in seconds
int lasttime = time;
while (active)
{
if (terminate) break;
try
{
if (!hasDeferredLinks())
{
isWaiting = true;
try { wait(100); } catch (InterruptedException fallthru) {}
}
isWaiting = false;
ltime = System.currentTimeMillis();
time = (int) (ltime / 1000);
if (lasttime != time)
{ // do things in here once per second
if ((lasttime % BLACKLIST_FLUSH_INTERVAL) == 0)
{ // get the black listed links a second chance every now and then
flushBlackList();
}
if (LockedLnkLst.size() > 0) checkAccessLockItems();
flushGroupCacheItems();
lasttime = time;
}
// below happens at 10 Hz ...
removeIdleTLinkBuckets(ltime);
deferredLinks.clear();
deferredTarget = null;
fecEntryWithTimeout = null;
synchronized (TLinkFactory.siblings)
{
for (int i=0; i<TLinkFactory.siblings.size(); i++)
{
checkLink(TLinkFactory.siblings.get(i),ltime);
}
}
for (int i = 0; i < numberTLinksInTable; i++)
{
if (linkTable[i] != null && linkTable[i] != tNullLink)
{
lnk = linkTable[i];
if (lnk.linkId != i && lnk.boundTo != null)
{
DbgLog.log("TFactoryWatchdogThread","link table id does not match entry index !");
}
checkLink(lnk,ltime);
}
}
if (deferredLinks.size() > 0)
{
TLink[] lnks = deferredLinks.toArray(new TLink[0]);
while (sendLinkRequest(lnks) > 0);
}
hasDeferredLinks = false;
}
catch (Exception e)
{
if (!active)
{ // program terminating ?
MsgLog.log("TFactoryWatchdogThread", "TLinkFactory no longer active", TErrorList.not_running, e, 0);
return;
}
e.printStackTrace();
MsgLog.log("TFactoryWatchdogThread", e.toString(), TErrorList.code_failure,e, 1);
}
}
removeAccessLock(null, null);
}
}
private int NotifyDeferredCallbacks()
{
TLink lnk;
for (int i = 0; i < numberTLinksInTable; i++)
{
if (linkTable[i] != null && linkTable[i] != tNullLink)
{
lnk = linkTable[i];
if (lnk.needsNotification)
{
synchronized (lnk)
{
if (lnk.terminate == false)
{
fireCallbackEvent("NotifyDeferredCallbacks", lnk);
}
lnk.needsNotification = false;
}
lnk.notifyAll(); // wake up the calling thread
}
}
}
return 0;
}
public int fillinIncomingData(TLink lnk)
{
String key = lnk.cntName == null ? null : "/"+lnk.cntName+"/"+lnk.expName;
int cc = fillinIncomingData(lnk.dOutput,key);
if (cc == 0 && lnk.relnkItem != null)
{ // remap the contents ?
if (lnk.relnkItem.getRelinkReason() == TErrorList.invalid_datarequest)
{
RelinkedItem rli = lnk.relnkItem;
TDataType dt = rli.getTargetDataObject();
lnk.dOutput.getData(); // fill in the link's data object
int len = lnk.dOutput.dCompletionLength;
cc = rli.tdt.getData(dt.getDataObject()); // map to destination
if (len < dt.dArrayLength) dt.dCompletionLength = len;
dt.setDataTimeStamp(lnk.dOutput.dTimestamp);
dt.setUserDataStamp(lnk.dOutput.usrDataStamp);
dt.setSystemDataStamp(lnk.dOutput.sysDataStamp);
}
else if (lnk.dOutput.getFormat() == TFormat.CF_STRUCT)
{
try
{
RelinkedItem rli = lnk.relnkItem;
TStructDescription sd = rli.getStructDescription();
if (sd == null) cc = TErrorList.invalid_structure_tag;
TStructDescription.Field f = sd.getField(rli.getField());
if (f == null) cc = TErrorList.invalid_field;
int len = lnk.dOutput.dCompletionLength;
int siz = f.getArraySize() * TFormat.formatSizeOf(f.getFormat());
int ssiz = sd.getSize();
int soff = f.getAddress();
byte[] src = (byte[])lnk.dOutput.getDataObject();
byte[] dst = new byte[len * siz];
TDataType dt = rli.getTargetDataObject();
for (int i=0; i<len; i++)
{
System.arraycopy(src, soff + i*ssiz, dst, i*siz, siz);
}
dt.setDataTimeStamp(lnk.dOutput.dTimestamp);
dt.setUserDataStamp(lnk.dOutput.usrDataStamp);
dt.setSystemDataStamp(lnk.dOutput.sysDataStamp);
dt.pushBytes(dst);
dt.setStructureKey(key);
cc = dt.getData();
}
catch (Exception ignore)
{ // just forward the completion code
lnk.canTimeout = true;
};
}
}
return cc;
}
public int fillinIncomingData(TDataType dtype)
{
return fillinIncomingData(dtype,null);
}
private int fillinIncomingData(TDataType dtype,String key)
{
Object hDataObject = dtype.getDataObject();
String bff = null;
switch (dtype.getFormat())
{
case TFormat.CF_STRING:
dtype.getData((String[]) hDataObject);
break;
case TFormat.CF_KEYVALUE:
dtype.getData((KEYVALUE[]) hDataObject);
break;
case TFormat.CF_STRUCT:
Object hStructObject = dtype.getStructObject();
TTaggedStructure ts = null;
boolean hasExtSpace = false;
if (hStructObject instanceof TTaggedStructure)
{
ts = (TTaggedStructure)hStructObject;
hasExtSpace = ts.hasExtendedSpace();
}
else if (hStructObject instanceof TTaggedStructure[])
{
ts = ((TTaggedStructure[])hStructObject)[0];
hasExtSpace = ts.hasExtendedSpace();
}
if (ts == null)
{
TStructDescription sd = TStructRegistry.get(dtype.getTag(),key);
hasExtSpace = (sd != null && sd.hasExtendedSpace());
}
if (dtype.getStructureKey() == null) dtype.setStructureKey(key);
//if (hasExtSpace) hDataObject = new byte[dtype.bytesin];
byte[] hBytes = hasExtSpace ? new byte[dtype.bytesin] : (byte[])hDataObject;
if (hBytes != null) dtype.getData((byte[])hBytes);
if (hStructObject instanceof TTaggedStructure)
{
((TTaggedStructure)hStructObject).toStruct(hBytes);
}
else if (hStructObject instanceof TTaggedStructure[])
{
TTaggedStructure[] tts = (TTaggedStructure[])hStructObject;
int dsiz = tts[0].getSizeInBytes();
for (int i = 0; i < tts.length; i++)
{
tts[i].toStruct(hBytes, i * dsiz, dsiz);
}
}
if (hBytes != hDataObject)
{
System.arraycopy(hBytes, 0, hDataObject, 0, ((byte[])hDataObject).length);
}
break;
case TFormat.CF_BITFIELD8:
case TFormat.CF_BITFIELD16:
case TFormat.CF_BITFIELD32:
case TFormat.CF_BITFIELD64:
bff = dtype.getField();
default:
if (hDataObject != null) dtype.getData(hDataObject);
if (bff != null) dtype.applyBitField();
break;
}
return 0;
}
public int fillinIncomingDataWithErrValue(TLink lnk)
{
if (lnk.linkStatus == 0) return 0;
if (lnk.useErrObject)
{
lnk.dOutput.dataCopy(lnk.dError);
return 0;
}
if (lnk.useErrValue)
{
lnk.dOutput.dataFill(lnk.linkErrValue);
if (lnk.linkErrString != null) lnk.dOutput.dataFill(lnk.linkErrString);
}
return 0;
}
protected TFecEntry fecEntryWithTimeout = null;
protected boolean allowSynchronousLinks = true;
protected boolean cannotNotifyFromWatchdogThread = false;
public void fireCallbackEvent(String msg,TLink lnk)
{
boolean trace = traceKey != null && lnk.isTraceLink();
if (trace)
{
lnk.traceLink("fireCallbackEvent", "is ready to fire callback (status "+lnk.linkStatus+")");
}
if (lnk.linkStatus < 0)
{
if (lnk.boundTo != null)
{ // some crazy jddd re-shuffling
if (lnk.boundTo.linkStatus < 0 && lnk.boundTo.lastLinkStatus < 0) return;
lnk.lastLinkStatus = lnk.boundTo.lastLinkStatus;
}
else
{
if (lnk.lastLinkStatus < 0) return;
lnk.linkStatus = lnk.lastLinkStatus;
}
}
if (!lnk.isWithinTolerance())
{
if (trace) lnk.traceLink("fireCallbackEvent", "needs to notify !");
lnk.isInsideCallback = true;
lnk.lastLinkNotification = System.currentTimeMillis();
if (debugLevel > 3)
DbgLog.log("TLinkFactory.fireCallbackEvent","fire callback for link "+lnk.getFullDeviceName()+"["+lnk.getProperty()+"] (id "+lnk.linkId+")");
try
{
if (lnk.tcb != null)
lnk.tcb.callback(lnk.callbackId,lnk.linkStatus);
else if (lnk.tlcb != null)
lnk.tlcb.callback(lnk);
else if (lnk.needsWakeUpCall)
lnk.wakeUpCall();
}
catch (Throwable e)
{
e.printStackTrace();
MsgLog.log(msg,"unhandled exception " + e.toString() + " inside link callback",TErrorList.runtime_error,e,0);
}
lnk.isInsideCallback = false;
if (lnk.linkStatus == TErrorList.reset_mca_property && !lnk.isMcaParent())
{ // force a re-issue of the link following the callback
if (trace) lnk.traceLink("fireCallbackEvent", "reset MCA information !");
MsgLog.log("TMcaLink.callback","received reset mca property signal for "+
lnk.getFullDeviceNameAndProperty(),lnk.linkStatus, null,1);
lnk.sub.starttime = (int)(System.currentTimeMillis()/1000);
lnk.linkCounter = RENEWAL_REMINDER-1;
lnk.sub.linkLastTime = 0;
}
}
else
{
if (trace) lnk.traceLink("fireCallbackEvent", "suppress callback information");
lnk.lastLinkSuppressedNotification = System.currentTimeMillis();
if (debugLevel > 3)
DbgLog.log("TLinkFactory.fireCallbackEvent","suppress callback for link "+lnk.getFullDeviceName()+"["+lnk.getProperty()+"] (id "+lnk.linkId+")");
}
lnk.hasNotifiedOnce = true;
lnk.hasObtainedStatus = true;
lnk.isLinkReassignment = false;
if (TErrorList.getErrorCode(lnk.linkStatus) == TErrorList.information_static)
{ // no reason to keep this link open
if (lnk.sub.mode != TMode.CM_REGISTER) lnk.close();
}
}
public void fireCallbackEventCheckDependencies(String msg,TLink lnk)
{
boolean trace = traceKey != null && lnk.isTraceLink();
if (trace) lnk.traceLink("fireCallbackEventCheckDependencies", "is ready to fire callback");
if (lnk.hasDependencies())
{ // chained dependencies ? -> do them first
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 ((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 = lnk.linkStatusSource;
fireCallbackEvent(msg,xlnk);
}
}
if (!lnk.isCancelledWithDependencies())
{
fireCallbackEvent(msg,lnk);
}
}
private int InterpretIncomingData(int transport,byte[] data, int length, InetAddress addr, int port, boolean deferCallbacks)
{
TLink lnk;
boolean hasData;
int n = 0;
TLink[] lnks = null;
synchronized (pHdr)
{ // this will run through everything that has come in and fill in the blanks
// also checking return code vs server_redirection, etc. ...
lnks = pHdr.toStruct(addr, port, data, length, transport);
}
if (lnks == null) return 0;
Thread.yield();
long ltime = System.currentTimeMillis();
if (debugLevel > 1)
DbgLog.log("InterpretIncomingData","recv " + length + " bytes "+lnks.length+" contracts");
try
{
for (int i = 0; i < lnks.length; i++)
{ // this is what just came in ...
lnk = lnks[i];
if (debugLevel > 1)
{
String dbgstr = "link " + lnk.linkId + "(" +
"/"+lnk.cntName+"/"+lnk.expName+"/"+lnk.devName +
"["+lnk.devProperty+"] : " +
(lnk.active ? "active" : "inactive") +
(lnk.linkStale ? " stale" : " not stale" +
" -> " + lnk.dOutput.blksin + " blks in from " +
lnk.dOutput.numblks + " <" + lnk.linkStatus + ">");
DbgLog.log("InterpretIncomingData",dbgstr);
}
if (!lnk.active)
{
if (TMode.getBaseMode(lnk.sub.mode) == TMode.CM_CANCEL)
{ // not active should always mean that the mode = CM_CANCEL
if (lnk.linkStatus != TErrorList.invalid_link &&
pHdr.lnkStarttime != TFecEntry.BCAST_ID &&
pHdr.lnkCounter > TContract.CTR_RENEWAL)
{ // not in a client-server 'cancel' loop and not a multicast subscription
sendLinkRequest(lnk);
}
}
continue;
}
if (!lnk.linkStale) continue;
lnk.linkStale = false;
lnk.linkPeer = addr;
// use the phs.subId to get the incoming link id !
if (lnk.dOutput.blksin == lnk.dOutput.numblks)
{ // ready to deal with !
n++;
lnk.sub.linkLastTime = ltime;
if (lnk.adjustDefaultValues)
{ // adjust contract upon first completion
int fmtsize = TFormat.formatSizeOf(lnk.dOutput.dFormat);
int dretsize = lnk.dOutput.bytesin;
if (lnk.linkStatus != 0) dretsize -= TDataType.RPCERR_SIZE;
// TODO: CF_STRING ?
if (dretsize > 0 && fmtsize > 0)
{
dretsize -= TFormat.getFormatHeaderSize(lnk.dOutput.dFormat);
lnk.dOutput.dArrayLength = dretsize / fmtsize;
}
lnk.adjustDefaultValues = false;
}
lnk.notifyPending = false;
if (lnk.linkStatus == TErrorList.get_subscription_id) continue;
if (lnk.linkStatus == 0 || (lnk.linkStatus & TErrorList.CE_SENDDATA) == TErrorList.CE_SENDDATA)
hasData = true;
else
hasData = false;
if (hasData)
{
if (debugLevel > 1)
DbgLog.log("InterpretIncomingData","call getData for link " + lnk.linkId + " format "
+ TFormat.toString(lnk.dOutput.getFormat()) + " "
+ TDataTime.toString(System.currentTimeMillis()));
// do something with it (events ?) ...
lnk.dOutput.isDataObjectInSync = false;
fillinIncomingData(lnk);
}
else
{
fillinIncomingDataWithErrValue(lnk);
}
lnk.hasObtainedStatus = true;
if (lnk.isGrouped())
{
TLinkGroup grp = lnk.getGroup();
//if (grp.getNumberPending() > 0) continue;
//grp.reset();
if (!grp.canNotify(lnk)) continue;
if (debugLevel > 1) DbgLog.log("InterpretIncomingData","all members of group have updated");
}
if (lnk.linkStatus >= 0)
{
if (lnk.linkStatus == TErrorList.illegal_property ||
lnk.linkStatus == TErrorList.non_existent ||
lnk.linkStatus == TErrorList.non_existent_elem ||
lnk.linkStatus == TErrorList.non_existent_fec )
{
boolean blacklistIt = !lnk.isWildcardLink;
if (lnk.linkStatus == TErrorList.non_existent_elem &&
lnk.linkTimeouts > 0) blacklistIt = false;
if (blacklistIt)
{
addLinkToBlackList(lnk);
if (debugLevel > 0)
DbgLog.log("InterpretIncomingData","add link " + lnk.getFullDeviceNameAndProperty() + " to black list");
}
else
{
if (debugLevel > 0)
DbgLog.log("InterpretIncomingData","link " + lnk.getFullDeviceNameAndProperty() + " returned " + TErrorList.getErrorString(lnk.linkStatus));
}
}
else
{ // reset this counter
lnk.linkBlacklists = 0;
}
lnk.notifyPending = true;
if (lnk.dOutput.timestamp == 0)
{
lnk.dOutput.timestamp = (int) (ltime / 1000);
lnk.dOutput.timestampMSEC = (int) (ltime % 1000);
lnk.dOutput.timestampUSEC = lnk.dOutput.timestampMSEC * 1000;
}
lnk.linkTimeouts = 0; // reset timeout counter
// if caller "cancel()s" then terminate is set to true (should be polite and tell the server).
// if the link automatically terminates (due to SINGLE -> CANCEL, etc.
// then the TMode is set to CM_CANCEL (don't need to tell the server)
if (lnk.sub.mode == TMode.CM_CANCEL) lnk.active = false;
if (lnk.isInAlarmState)
{
lnk.isInAlarmState = false;
if (autoLinkErrorAlarms && isRunningAsServer())
{ // remove any link error alarms
getEquipmentModuleFactory().clearFecLinkErrorAlarm(lnk);
}
}
// set notification flag:
if (lnk.linkStatusLastNotification != lnk.linkStatus)
{
MsgLog.log("InterpretIncomingData",
lnk.getFullDeviceName()+"["+lnk.getProperty()+"] link status changed from "+
TErrorList.getErrorString(lnk.linkStatusLastNotification)+" to "+TErrorList.getErrorString(lnk.linkStatus),
lnk.linkStatus,null,1);
lnk.linkStatusLastNotification = lnk.linkStatus;
if (lnk.linkStatus == 0)
{ // is now successful again !
lnk.hasNotifiedOnce = false;
}
}
lnk.needsNotification = true;
lnk.dOutput.bytesin = 0; // reset here !
if (!lnk.getCriticalSection()) continue;
synchronized (lnk)
{
try
{
if (lnk.active == true)
{
if (!lnk.hasNotifiedOnce)
{ // first round of callbacks ...
if (autoLinkWatchdogs && TWatchdogLink.isWatchableLink(lnk))
{
lnk.needsToStartLinkWatchdog = true;
}
}
if (!deferCallbacks || lnk.isWildcardLink)
{
isInsideCallback = true;
if (lnk.hasDependencies() && !lnk.isMcaParent())
{ // chained dependencies (but not MCA links) ? -> do them first
Hashtable<TLink,Thread> tht = new Hashtable<TLink,Thread>();
Thread th;
TLink xlnk;
TDataType xlnkData;
LinkedList<TLink> xlst = lnk.getDependencies();
for (int k=0; xlst != null && k < xlst.size(); k++)
{
xlnk = (TLink)xlst.get(k);
if (xlnk == null || xlnk.sub == null) continue;
if ((xlnkData=xlnk.getOutputDataObject()) != null)
{
xlnkData.dataCopy(lnk.dOutput);
String key = lnk.cntName == null ? null : "/"+lnk.cntName+"/"+lnk.expName;
xlnkData.setStructureKey(key);
xlnkData.getData(); // Karol, 03.12.2009
xlnkData.setDataTimeStamp(lnk.dOutput.getDataTimeStamp());
}
xlnk.sub.linkLastTime = lnk.sub.linkLastTime;
xlnk.linkStatus = lnk.linkStatus;
fireCallbackEvent("InterpretIncomingData",xlnk);
if ((th=xlnk.getThread()) != lnk.getThread())
{ // if dependent links belong to different threads than the parent !
if (!tht.containsValue(th)) tht.put(xlnk, th);
}
}
if (tht.size() > 0)
{ // synchronous calls depend on being 'notified' to stop waiting!
for (TLink k : tht.keySet()) k.wakeUpCall();
}
}
if (!lnk.isCancelledWithDependencies())
{
fireCallbackEvent("InterpretIncomingData",lnk);
}
isInsideCallback = false;
}
lnk.needsNotification = false;
}
else
{
lnk.sub.mode = TMode.CM_CANCEL;
}
// wake up the calling thread
if (!lnk.isWildcardLink) lnk.notifyAll();
}
catch (Throwable e)
{
e.printStackTrace();
MsgLog.log("InterpretIncomingData","unexpected exception",TErrorList.code_failure,e,0);
}
}
if ((lnk.devAccess & TAccess.CA_SYNC) != 0 && TMode.getBaseMode(lnk.sub.mode) == TMode.CM_SINGLE)
{
if (debugLevel > 1)
DbgLog.log("InterpretIncomingData","cancel single link ("+lnk.linkId+") "+lnk.getFullDeviceNameAndProperty());
if ((lnk.sub.mode & TMode.CM_CONNECT) == TMode.CM_CONNECT)
{
lnk.sub.mode = (short) (TMode.CM_CANCEL | TMode.CM_CONNECT);
}
else
{
lnk.sub.mode = TMode.CM_CANCEL; // turn off the link
lnk.active = false;
}
if (lnk.removeOnClose)
{ // don't cause link removal here !
if (debugLevel > 1)
DbgLog.log("InterpretIncomingData","mark link ("+lnk.linkId+") "+lnk.getFullDeviceNameAndProperty()+ " for termination");
lnk.terminate = true; // let the watchdog thread flush the table
}
}
if (lnk.sub.mode == TMode.CM_SINGLE)
{ // async single link (not connected)
if (debugLevel > 1)
DbgLog.log("InterpretIncomingData","de-activate single link ("+lnk.linkId+") "+lnk.getFullDeviceNameAndProperty());
if (!lnk.keepActive) lnk.active = false;
lnk.keepActive = false;
}
lnk.freeCriticalSection();
}
// need to re-establish the link ?
if (debugLevel > 2)
DbgLog.log("InterpretIncomingData","link ("+lnk.linkId+") "+lnk.getFullDeviceNameAndProperty()+" Link counter: " + lnk.linkCounter + " at " + ltime);
checkLinkRenewalCondition(lnk);
}
}
}
catch (Exception e)
{
e.printStackTrace();
MsgLog.log("InterpretIncomingData","processing error",TErrorList.code_failure,e,0);
}
for (int i = 0; i < lnks.length; i++) lnks[i].canTimeout = true;
return 0;
}
private boolean delayLinkRenewals = true;
public void setDelayLinkRenewals(boolean value)
{
delayLinkRenewals = value;
}
public boolean getDelayLinkRenewals()
{
return delayLinkRenewals;
}
public void checkLinkRenewalCondition(TLink lnk)
{ // reset counter if < RENEWAL_REMINDER !!!!
if (!lnk.active) return;
int renewalMultiplier = TSubscription.getRenewalMultiplier(lnk.renewalMultiplier, lnk.sub.pollingInterval);
if (lnk.sub.isLegacy && renewalMultiplier > 4) renewalMultiplier = 4;
if (TMode.getBaseMode(lnk.sub.mode) > TMode.CM_SINGLE &&
lnk.linkCounter > 0 &&
lnk.linkCounter < renewalMultiplier*RENEWAL_REMINDER &&
lnk.linkStatus != TErrorList.link_blacklisted)
{ // a persistent link !
if (!lnk.hasRenewed || lnk.linkCounter < renewalMultiplier*RENEWAL_URGENT)
{
if (delayLinkRenewals &&
!lnk.needsToStartLinkWatchdog &&
lnk.linkCounter > RENEWAL_URGENT)
{
if (debugLevel > 1)
DbgLog.log("InterpretIncomingData","post link renewal ("+lnk.linkId+") "+lnk.getFullDeviceNameAndProperty());
lnk.delayEstablishLink(true);
lnk.setIsRenewal(true);
return;
}
lnk.hasRenewed = true;
int sts = lnk.linkStatus;
if (debugLevel > 1)
DbgLog.log("InterpretIncomingData","send link renewal ("+lnk.linkId+") "+lnk.getFullDeviceNameAndProperty());
sendLinkRequest(lnk);
lnk.linkStatus = sts; // P.D. 6.4.08 : smooth things out regarding the link status
}
}
else
{
lnk.hasRenewed = false;
}
}
private int InterpretIncomingGlobalsData(InetAddress gaddr, byte[] data, int length, boolean deferCallbacks)
{
TLink glb;
TLink[] lnks = null;
synchronized (glbHdr)
{
lnks = glbHdr.toStruct(gaddr, data, length);
}
if (lnks == null) return 0;
if (debugLevel > 1) DbgLog.log("InterpretIncomingGlobalsData","glb recv " + length + " bytes, "+lnks.length+" global links");
for (int i = 0; i < lnks.length; i++)
{
glb = lnks[i];
if (glb.sub.mode == TMode.CM_GLOBAL)
{
glb.sub.linkLastTime = System.currentTimeMillis();
glb.notifyPending = false;
if (debugLevel > 2) DbgLog.log("InterpretIncomingGlobalsData","call getData for format " + glb.dOutput.getFormat());
if (glb.linkStatus >= 0 && glb.notifyPending == false)
{
glb.notifyPending = true;
//glb.dOutput.timestamp = time; <<< this was assigned in glbHdr.toStruct() !
glb.linkTimeouts = 0; // reset timeout counter
// if caller "cancel()s" then terminate is set to true
// if the link automatically terminates (due to SINGLE -> CANCEL,etc.
// then the TMode is set to CM_CANCEL (don't need to tell the server)
if (glb.linkStatusLastNotification != glb.linkStatus)
{
MsgLog.log("InterpretIncomingGlobalsData",
glb.getFullDeviceName()+"["+glb.getProperty()+"] link status changed from "+
TErrorList.getErrorString(glb.linkStatusLastNotification)+" to "+TErrorList.getErrorString(glb.linkStatus),
glb.linkStatus,null,1);
glb.linkStatusLastNotification = glb.linkStatus;
}
if (glb.isInAlarmState)
{
glb.isInAlarmState = false;
if (autoLinkErrorAlarms && isRunningAsServer())
{ // remove any link error alarms
getEquipmentModuleFactory().clearFecLinkErrorAlarm(glb);
}
}
glb.needsNotification = true;
synchronized (glb)
{
try
{
if (glb.terminate == false)
{
isInsideCallback = true;
if (glb.hasDependencies())
{ // chained dependencies ? -> do them first
TLink xlnk;
TDataType xlnkData;
LinkedList<TLink> xlst = glb.getDependencies();
for (int k=0; k < xlst.size(); k++)
{
xlnk = (TLink)xlst.get(k);
if ((xlnkData=xlnk.getOutputDataObject()) != null)
{
xlnkData.dataCopy(glb.dOutput);
xlnkData.setDataTimeStamp(glb.dOutput.getDataTimeStamp());
}
xlnk.sub.linkLastTime = glb.sub.linkLastTime;
xlnk.linkStatus = glb.linkStatus;
fireCallbackEvent("InterpretIncomingGlobalsData", xlnk);
}
}
if (!glb.isCancelledWithDependencies())
{
fireCallbackEvent("InterpretIncomingGlobalsData", glb);
}
isInsideCallback = false;
}
glb.notifyAll(); // wake up the calling thread
}
catch (Exception e)
{
e.printStackTrace();
MsgLog.log("InterpretIncomingGlobalsData","unhandled execption"+e.toString(),TErrorList.runtime_error,e,0);
}
}
}
}
glb.hasObtainedStatus = true;
}
return 0;
}
public class TFactoryThread extends Thread
{
TPacket tp;
boolean isWaiting = false;
boolean canCallback = false;
String tag = null;
TFactoryThread(TPacket tPacket,String tag,boolean canFireCallback)
{
this.tag = tag;
tp = tPacket;
canCallback = canFireCallback;
String s = null;
MulticastSocket sck;
if ((sck=tp.getSocket()) != null)
{
String dsc = tp.isMulticastListener() ? "(multicast listener) " : "";
s = new String(" datagram port " + dsc + sck.getLocalPort());
}
else s = new String(" unbound socket ?");
this.setName("Link Factory "+tag+s);
//this.setPriority(MAX_PRIORITY);
}
public synchronized void run()
{
MsgLog.log("TFactoryThread","Link Factory Thread " + getName() + " started ...",0,null,1);
MulticastSocket sck = tp.getSocket();
if (sck == null)
{
MsgLog.log("TFactoryThread", "unable to obtain "+tag+" socket!",TErrorList.code_failure,null,0);
return;
}
while (active)
{
if (terminate) break;
if (debugLevel > 1) DbgLog.log("TFactoryThread","Waiting for data ...");
try
{
isWaiting = true;
tp.dpIn.setLength(TPacket.MAX_DATAGRAM_SIZE); // reset the receive buffer length
if (sck != null)
{
sck.receive(tp.dpIn);
}
totalConnectionArrivals++;
isWaiting = false;
// got it, now interpret it ...
if (debugLevel > 1) DbgLog.log("TFactoryThread","examine " + tp.dpIn.getLength() + " bytes");
InterpretIncomingData(TTransport.UDP,tp.dpIn.getData(), tp.dpIn.getLength(), tp.dpIn.getAddress(),tp.dpIn.getPort(),!canCallback);
}
catch (IOException e)
{
MsgLog.log("TFactoryThread",e.toString(),TErrorList.io_error,e,1);
}
catch (Exception e)
{
if (debugLevel > 0) e.printStackTrace();
MsgLog.log("TFactoryThread",e.toString(),TErrorList.code_failure,e,0);
}
}
}
}
public class TFactoryGlobalsThread extends Thread
{
TPacket tp;
boolean isWaiting = false;
TFactoryGlobalsThread(TPacket tPacket)
{
tp = tPacket;
String s = null;
MulticastSocket sck = tp.getSocket();
if (sck != null) s = new String("globals port (multicast listener) " + sck.getLocalPort());
else s = new String("globals unbound socket ?");
this.setName("Link Factory " + s);
}
public synchronized void run()
{
MsgLog.log("TFactoryGlobalsThread","Link Factory Thread " + getName() + " started ...",0,null,1);
MulticastSocket sck = tp.getSocket();
if (sck == null)
{
MsgLog.log("TFactoryGlobalsThread", "unable to obtain globals socket!",TErrorList.code_failure,null,0);
return;
}
while (active)
{
if (terminate) break;
if (debugLevel > 1) DbgLog.log("TFactoryGlobalsThread","Waiting for globals data ...");
try
{
isWaiting = true;
tp.dpIn.setLength(TTransport.UDP_BUFFER_SIZE); // reset the receive buffer length
sck.receive(tp.dpIn);
isWaiting = false;
// got it, now interpret it ...
InterpretIncomingGlobalsData(tp.dpIn.getAddress(), tp.dpIn.getData(), tp.dpIn.getLength(), false);
}
catch (IOException e)
{
if (debugLevel > 1) DbgLog.log("TFactoryGlobalsThread", "IO exception: "+e.getMessage());
}
catch (Exception e)
{
e.printStackTrace();
MsgLog.log("TFactoryGlobalsThread", "unhandled exception "+e.toString(),TErrorList.code_failure,e,0);
}
}
}
}
/**
* TLinkFactory constructor comment.
*/
private TLinkFactory()
{
initFactory();
}
private static boolean factoryHasInitialzed = false;
private void initFactory()
{
if (factoryHasInitialzed) return;
MsgLog.log("initFactory","TLink factory initializing ...",0,null,1);
//System.setSecurityManager(null);
// get the socket settings here ...
sckRcvBufferSize = initializerInstance.getClnRcvBufferSize();
sckSndBufferSize = initializerInstance.getClnSndBufferSize();
sckTimeToLive = initializerInstance.getSckTimeToLive();
atp = new TPacket(0,sckRcvBufferSize,sckSndBufferSize,sckTimeToLive);
stp = new TPacket(0,sckRcvBufferSize,sckSndBufferSize,sckTimeToLive);
qtp = new TPacket();
nmtp = new TPacket();
pHdr = new TPHdr(this);
glbHdr = new TGlobalsHdr(this);
stfThrd = new TFactoryThread(stp,"sync",false);
qtfThrd = new TFactoryThread(qtp,"query",false);
atfThrd = new TFactoryThread(atp,"async",true);
gtfThrd = null;
active = true;
stfThrd.start();
qtfThrd.start();
atfThrd.start();
tfwdThrd.setPriority(Thread.MIN_PRIORITY);
tfwdThrd.start();
String dbglvlStr;
if ((dbglvlStr = System.getProperty("debug.level")) != null)
{
try { debugLevel = Integer.parseInt(dbglvlStr);} catch (Exception ignore) {}
}
String env = System.getProperty("tine.transport");
if (env == null) env = System.getenv("TINE_TRANSPORT");
if (env != null)
{
if (env.substring(0,3).compareToIgnoreCase("TCP") == 0)
{
useConnectedSockets = true;
}
}
env = System.getProperty("tine.");
if (env == null) env = System.getenv("TINE_STANDALONE");
if (env != null)
{
gSystemRunningStandAlone = (env.compareToIgnoreCase("TRUE") == 0);
initializer.setENSAddress(null);
MsgLog.log("TLink Factory","is running in stand-alone mode: "+gSystemRunningStandAlone,0,null,0);
}
env = System.getProperty("tine.networkaddress.resolution");
if (env == null) env = System.getenv("TINE_NETWORKADDRESS_RESOLUTION");
if (env != null)
{
setAllowNetworkAddressResolution((env.compareToIgnoreCase("TRUE") == 0));
MsgLog.log("TLink Factory","allow network address resolution: "+allowNeworkAddressResolution(),0,null,0);
}
env = System.getProperty("tine.delay.link.renewal");
if (env == null) env = System.getenv("TINE_DELAY_LINK_RENEWAL");
if (env != null)
{
setDelayLinkRenewals((env.compareToIgnoreCase("TRUE") == 0));
MsgLog.log("TLink Factory","delay link renewals: "+getDelayLinkRenewals(),0,null,0);
}
env = System.getProperty("doocs.name");
if (env == null) env = System.getProperty("doocs.user");
if (env == null) env = System.getenv("DOOCS_USER");
if (env != null) setDoocsUserName(env);
Runtime.getRuntime().addShutdownHook(factoryShutdownHook);
boolean irc = initializerInstance.isRichClient();
if (irc != isRichClient) setRichClient(irc);
factoryHasInitialzed = true;
}
Thread factoryShutdownHook = new TLinkFactoryShutdown();
/**
* unpins and closes any background globals links that were
* started due to synchronous calls to a known globals server.
*/
public void closeBackgroundGlobalsLinks()
{
for (int i = 1; i < numberTLinksInTable; i++)
{
if (linkTable[i] == null) continue;
if (linkTable[i] == tNullLink) continue;
if (linkTable[i].isGlobalsLinkPinned)
{
linkTable[i].isGlobalsLinkPinned = false;
cancel(linkTable[i],true);
}
}
}
/*
* cancel() terminates an active link
*
* @param lnk is the link to cancel
*/
public int cancel(TLink lnk)
{
return cancel(lnk,true);
}
private void unlinkMcaParent(TLink lnk)
{ // already synchronized on mcaLst ...
lnk.removedFromMcaList = 0;
mcaLst.remove(lnk.getFullDeviceNameAndProperty());
if (lnk.boundTo != null)
{ // the mca parent is a bound link -> remove the dependency and leave ...
lnk.boundTo.rmvDependency(lnk.boundTo);
lnk.boundTo = null;
return;
}
MsgLog.log("unlinkMcaParent", "closing MCA parent link "+lnk.getFullDeviceNameAndProperty(),0,null,1);
cancel(lnk,true);
}
/*
* cancel() terminates an active link
*
* @param lnk is the link to cancel
* @param removeFromTable determines whether the link is to be
* removed from the link table or not. If not, the link remains
* in the table as a place holder.
*/
public int cancel(TLink lnk,boolean removeFromTable)
{ synchronized(lnkTblObject) {
boolean trace = traceKey != null && lnk.isTraceLink();
if (trace) lnk.traceLink("TLinkFactory.cancel", "closing link (remove from table : "+removeFromTable+")");
if (lnk == null || lnk.sub == null)
{ // never allocated
if (lnk != null) lnk.active = false;
return 0;
}
lnk.keepActive = false;
if (autoLinkErrorAlarms && isRunningAsServer())
{ // remove any link error alarms
getEquipmentModuleFactory().clearFecLinkErrorAlarm(lnk);
}
if (lnk.isGlobalsLinkPinned)
{ // keep alive
if (trace) lnk.traceLink("TLinkFactory.cancel", "globals link is pinned!");
return 0;
}
InetAddress g;
if ((g=lnk.getMulticastGroup()) != null)
{ // canceling a multicast link
if (numLinksInMulticastGroup(g) == 1)
{ // last one in the group !
detachMulticastGroup(lnk.isGlobalsLink,g);
if (trace) lnk.traceLink("TLinkFactory.cancel", "detach from multicast group");
}
lnk.setMulticastGroup(null);
if (lnk.isGlobalsLink) lnk.active = false;
}
TLink thisLnk = lnk;
int mcaidx = lnk.getMcaIndex();
if (mcaidx > 0)
{ // this is an mca link element
if (trace) lnk.traceLink("TLinkFactory.cancel", "is an MCA element");
TLink parent = lnk.getBoundLink();
TMcaLink mca = parent == null ? null : getMcaLink(parent.cntName,parent.expName,parent.devName,parent.devProperty);
if (mca != null)
{ // remove this dependent link
if (!lnk.isInsideCallback && !parent.isInsideCallback)
{
if (trace) lnk.traceLink("TLinkFactory.cancel", "remove from parent "+parent.getFullDeviceNameAndProperty());
mca.remove(lnk);
lnk.setMcaIndex(0);
lnk.setMcaDevice(null);
lnk.setBoundLink(null);
}
lnk.getSubscription().mode = TMode.CM_CANCEL;
}
else
{
if (trace) lnk.traceLink("TLinkFactory.cancel", "bound mca link without parent !");
MsgLog.log("TLinkFactory.cancel", "bound mca link without parent",TErrorList.link_error,null,0);
return TErrorList.link_error;
}
lnk.active = false;
lnk.terminate = removeFromTable;
if (mca.lnks.size() == 0)
{ // last one -> remove the mca link
parent.removedFromMcaList = (int)(System.currentTimeMillis()/1000);
MsgLog.log("TLinkFactory.cancel", "mark mca parent "+parent.getFullDeviceNameAndProperty()+" for removal",0,null,1);
if (trace) lnk.traceLink("TLinkFactory.cancel", "remove MCA parent "+parent.getFullDeviceNameAndProperty());
return 0;
}
else
{ // just return
return 0;
}
}
if (lnk.isBound())
{ // this one is just bound to another link (don't cancel for real: don't send CM_CANCEL)
lnk.active = false;
thisLnk = lnk.getBoundLink();
thisLnk.rmvDependency(lnk);
if (trace) lnk.traceLink("TLinkFactory.cancel", "link is bound to "+thisLnk.getFullDeviceNameAndProperty());
if (!thisLnk.hasDependencies())
{ // that was the last dependency, was the link canceled with dependencies ?
if (trace) lnk.traceLink("TLinkFactory.cancel", "last dependent link -> cancel "+thisLnk.getFullDeviceNameAndProperty());
if (!thisLnk.isCancelledWithDependencies()) return 0; // still active
}
else
{
return 0;
}
}
if (thisLnk.hasDependencies())
{ // primary link canceled, but there are still some hangers on ...
if (trace) lnk.traceLink("TLinkFactory.cancel", "primary link still has dependencies!");
thisLnk.cancelledWithDependencies = true;
return 0;
}
if (thisLnk.isWildcardLink && thisLnk.twcl != null)
{ // closing a wildcard link
if (trace) lnk.traceLink("TLinkFactory.cancel", "wild card link!");
boolean earlyExit = false;
TWildcardLink wc = thisLnk.twcl;
thisLnk.twcl = null;
wc.list = null;
if (wc.length > 0)
{ // not a single server link
earlyExit = true;
for (int i=0; i<wc.length; i++)
{ // this will re-enter this routine -> null out the twcl reference first!
wc.links[i].close();
}
wc.length = 0;
thisLnk.active = false;
thisLnk.terminate = removeFromTable;
thisLnk.notifyPending = false;
}
rmvWildcardLink(wc);
if (earlyExit) return 0;
}
if (thisLnk.sub == null) return 0;
boolean isInformationStatic = (TErrorList.getErrorCode(thisLnk.linkStatus) == TErrorList.information_static);
if (isInformationStatic && thisLnk.isInsideCallback)
{ // callback has called close() !
thisLnk.linkStatus = 0; // avoid calling the post-callback .close()
isInformationStatic = false; // don't need special tricks below
}
short bmode = TMode.getBaseMode(thisLnk.sub.mode);
if (TMode.canClose(bmode))
{
if (trace) lnk.traceLink("TLinkFactory.cancel", "link is allowed to close");
MsgLog.log("cancel","cancel link ("+thisLnk.linkId+") "+thisLnk.getFullDeviceNameAndProperty()+" mode was "
+ TMode.toString(thisLnk.sub.mode),0,null,1);
if ((thisLnk.sub.mode & TMode.CM_CONNECT) == TMode.CM_CONNECT)
{
thisLnk.sub.mode = TMode.CM_CANCEL | TMode.CM_CONNECT;
}
else
{
thisLnk.sub.mode = TMode.CM_CANCEL; // turn off the link
}
if (thisLnk.active && thisLnk.linkStatus != TErrorList.link_timeout)
{ // if the server is down then no need to tell him we're closing the link
if (thisLnk.canSendPacked() && !isInformationStatic) thisLnk.delayEstablishLink(true);
sendLinkRequest(thisLnk);
if (trace) lnk.traceLink("TLinkFactory.cancel", "notify server of closing action");
}
}
if (isInformationStatic)
{
thisLnk.removeOnClose = (thisLnk.sub.mode == TMode.CM_REGISTER);
thisLnk.sub.mode = TMode.CM_REGISTER;
}
thisLnk.active = false;
if (thisLnk.linkId == 0)
{
thisLnk.removeOnClose = false; // just in case
synchronized (siblings)
{
if (siblings.contains(thisLnk))
{
MsgLog.log("TLinkFactory.cancel", "remove ENS sibling",0,null,1);
siblings.remove(thisLnk);
if (trace) lnk.traceLink("TLinkFactory.cancel", "remove ENS sibling");
}
}
}
else
{
thisLnk.terminate = removeFromTable;
if (trace) lnk.traceLink("TLinkFactory.cancel", "mark for removal");
}
thisLnk.notifyPending = false;
return 0;
} }
public TLink findLinkWithOutputDataType(TDataType dout)
{
for (int i = 1; i < numberTLinksInTable; i++)
{
if (linkTable[i] == null) continue;
if (linkTable[i] == tNullLink) continue;
if (!linkTable[i].active) continue;
if (linkTable[i].dOutput == dout) return linkTable[i];
}
return null;
}
TLink getExistingLink(String devname, String devproperty, TDataType dout, TDataType din, short devaccess)
{
for (int i = 1; i < numberTLinksInTable; i++)
{
if (linkTable[i] == null) continue;
if (linkTable[i] == tNullLink) continue;
if (!linkTable[i].active) continue;
if (linkTable[i].getFullDeviceName().compareToIgnoreCase(devname) != 0) continue;
if (linkTable[i].getProperty().compareToIgnoreCase(devproperty) != 0) continue;
if (TAccess.toBase(linkTable[i].devAccess) != TAccess.toBase(devaccess)) continue;
if (!linkTable[i].getOutputDataObject().equals(false,dout)) continue;
if (!linkTable[i].getInputDataObject().equals(true,din)) continue;
return linkTable[i];
}
return null;
}
TLink getExistingLink(TLink thisLink, TDataType dout, TDataType din)
{
boolean fixdef = true;
for (int i = 1; i < numberTLinksInTable; i++)
{
if (linkTable[i] == null) continue;
if (linkTable[i] == thisLink) continue;
if (linkTable[i] == tNullLink) continue;
if (!linkTable[i].active) continue;
//if (linkTable[i].boundTo != null) continue; // this one already bound
if (linkTable[i].isRedirected || thisLink.isRedirected)
{ // one or both of them is redirected
RedirectedItem rt = getRedirectionInformation(thisLink);
RedirectedItem ri = getRedirectionInformation(linkTable[i]);
if (ri == null)
{ // table entry not redirected
String lkey = getLinkKey(linkTable[i]);
if (lkey.compareToIgnoreCase(thisLink.rdrKey) != 0) continue;
}
else if (rt == null)
{ // this link not redirected
String lkey = getLinkKey(thisLink);
if (lkey.compareToIgnoreCase(linkTable[i].rdrKey) != 0) continue;
}
else
{ // both redirected
if (!rt.destinationEquals(ri)) continue;
}
}
else
{
if (linkTable[i].srvAddr.fecName == null || thisLink.srvAddr.fecName == null) continue;
if (linkTable[i].srvAddr.eqmName == null || thisLink.srvAddr.eqmName == null) continue;
if (linkTable[i].srvAddr.fecName.compareTo(thisLink.srvAddr.fecName) != 0) continue;
if (linkTable[i].srvAddr.eqmName.compareTo(thisLink.srvAddr.eqmName) != 0) continue;
if (linkTable[i].getDeviceName().compareToIgnoreCase(thisLink.getDeviceName()) != 0) continue;
if (linkTable[i].getProperty().compareToIgnoreCase(thisLink.getProperty()) != 0) continue;
}
if (TAccess.toBase(linkTable[i].devAccess) != TAccess.toBase(thisLink.devAccess)) continue;
if (!linkTable[i].getInputDataObject().equals(true,din)) continue;
fixdef = !linkTable[i].isMcaParent();
//if (linkTable[i].isMcaParent()) fixdef = false;
if (!linkTable[i].getOutputDataObject().equals(false,fixdef,dout)) continue;
if (linkTable[i].boundTo != null && linkTable[i].boundTo.active)
{ // try to cut to the chase concerning known MCA information
int mcaidx = linkTable[i].getMcaIndex();
if (mcaidx < 1) continue; // this one already bound and not an MCA element
thisLink.setMcaIndex(mcaidx);
thisLink.setMcaDevice(linkTable[i].getMcaDevice());
// the 3 statements below should be covered by fixdef = true above !
thisLink.dOutput.setArrayLength(1);
thisLink.dOutput.dCompletionLength = 1;
thisLink.dOutput.dFormat = linkTable[i].getOutputDataObject().dFormat;
TMcaLink mca = TLinkFactory.getMcaLink(linkTable[i].cntName,linkTable[i].expName,linkTable[i].getMcaDevice(),linkTable[i].devProperty);
if (mca == null) continue; // ??
thisLink.sub = new TSubscription(linkTable[i].sub.contract, thisLink);
thisLink.con = linkTable[i].con;
thisLink.reqHdr = linkTable[i].reqHdr;
thisLink.boundTo = linkTable[i].boundTo;
thisLink.primary = linkTable[i]; // when 2 mca single element links are identical !
thisLink.linkId = registerLink(thisLink); // must (!) put this in the link table (not an ordinary bound link)
linkTable[thisLink.linkId] = thisLink;
mca.add(thisLink);
if (TLinkFactory.debugLevel > 2)
DbgLog.log("getExistingLink", "add "+thisLink.getFullDeviceNameAndProperty()+" (id "+thisLink.linkId+")" + " to mca parent "+mca.getParent().getFullDeviceNameAndProperty()+" (id "+mca.getParent().linkId+")");
return linkTable[i].getBoundLink(); // will be assigned in makeLink()
}
return linkTable[i];
}
return null;
}
/**
* Put a new TLink in the link table.
* Calling this method directly bypasses various system
* checks for cdi hooks, duplicate links, etc.
* A direct call is generally used internally for address queries from the ENS.
*
* @return TLink
*/
public TLink simpleLink(String devname, String devproperty, TDataType dout, TDataType din, short devaccess)
{ // called only by TSrvEntry.getSrvAddrFromENS()
int i;
if (devname.startsWith("ENS"))
{ // given without context => internal queries
i = 0;
adjustLinkTable(new TLink(0, devname, devproperty, dout, din, devaccess),adjustLinkTableAdd);
}
else
{ // add a place holder in the link table
if ((i=adjustLinkTable(new TLink(0, devname, devproperty, dout, din, devaccess),adjustLinkTableAdd)) < 0)
return null;
}
// re-assign the place-holder ...
if (debugLevel > 1) DbgLog.log("simpleLink","creating TLink " + linkTable[i] + " (" + i + ")");
if (debugLevel > 0) linkTable[i].setDebugLevel(debugLevel);
if (i == 0) linkTable[0].removeOnClose = false; // here it is again !
return linkTable[i];
}
private void detachMulticastGroup(boolean isGlobalLink,InetAddress g)
{
if (g == null) return;
if (g.equals(initializer.getMCastAddress()) ||
g.equals(initializer.getGCastAddress()))
return; // stay joined to the canonical groups
try
{
TPacket tp = isGlobalLink ? getGlobalsSocket() : getMulticastSocket();
tp.getSocket().leaveGroup(g);
}
catch (IOException e)
{
MsgLog.log("detachMulticastGroup","could not detach from multicast group : " + e.getMessage(),TErrorList.io_error,e,0);
}
}
private int numLinksInMulticastGroup(InetAddress g)
{
int n = 0;
InetAddress mcg;
for (int i=0; i<numberTLinksInTable; i++)
{
if (linkTable[i] == null ||
(mcg=linkTable[i].getMulticastGroup()) == null) continue;
if (mcg.equals(g)) n++;
}
return n;
}
private ByteArrayOutputStream sndLnkByteStream = null;
private int sendLinkBytesToPeer(TLink lnk,ByteArrayOutputStream bs) throws IOException
{
boolean isSynchronous = ((lnk.devAccess & TAccess.CA_SYNC) != 0);
boolean isQuery = lnk.isQueryLink();
boolean isServiceRequest = ((lnk.sub.contract.eqmName.compareTo(TSrvEntry.SRVEQM_NAME)) == 0);
TFecEntry srv = lnk.srvAddr.fecAddr;
if (srv == null)
{
if (debugLevel > 0) DbgLog.log("sendLinkRequest","establish link : can't resolve server address");
lnk.active = false;
return TErrorList.non_existent_fec;
}
if (TMode.isConnected(lnk.sub.mode))
{
if (lnk.tb == null) lnk.tb = new TLinkBucket(lnk);
if (lnk.tb.isDeactivating) return TErrorList.tcp_connect_error;
if (lnk.tb.getSocket() != null)
{
OutputStream os = lnk.tb.getOutputStream();
os.write(bs.toByteArray());
os.flush();
}
else
{
lnk.tb = null;
return TErrorList.tcp_connect_error;
}
}
else if (isSynchronous && isQuery)
{
qtp.dpOut = new DatagramPacket(bs.toByteArray(), bs.size(), srv.fecHost, initializer.getSrvPort()
+ srv.fecPortOffset);
qtp.getSocket().send(qtp.dpOut);
}
else if (isSynchronous)
{
if (isServiceRequest)
{
stp.dpOut = new DatagramPacket(bs.toByteArray(), bs.size(), srv.fecHost, initializer.getNetCastPort());
}
else
{
stp.dpOut = new DatagramPacket(bs.toByteArray(), bs.size(), srv.fecHost, initializer.getSrvPort()
+ srv.fecPortOffset);
}
stp.getSocket().send(stp.dpOut);
}
else
{
atp.dpOut = new DatagramPacket(bs.toByteArray(), bs.size(), srv.fecHost, initializer.getSrvPort()
+ srv.fecPortOffset);
atp.getSocket().send(atp.dpOut);
}
return 0;
}
/*
* sends just this link request (no packing)
* @param lnk the TLink to send
* @return link status
*/
int sendLinkRequest(TLink lnk)
{ synchronized(lnkTblObject) {
if (lnk == null || lnk == tNullLink)
{
return TErrorList.non_existent;
}
boolean trace = TLinkFactory.traceKey != null && lnk.isTraceLink();
if (trace)
{
lnk.traceLink("sendLinkRequest", "sending link request");
}
if (lnk.linkStatus == TErrorList.link_blacklisted)
{
lnk.sub.linkLastTime = System.currentTimeMillis();
if (trace) lnk.traceLink("sendLinkRequest", "link is blacklisted");
return TErrorList.link_blacklisted;
}
if (lnk.delayEstablishLink)
{
if (trace) lnk.traceLink("sendLinkRequest", "delay link request (pack collection)");
return 0;
}
if (lnk.sub.contract == null || lnk.sub.contract.eqmName == null)
{
if (trace) lnk.traceLink("sendLinkRequest", "subscription contains null entries !");
return TErrorList.link_error;
}
if (lnk.linkId < 0)
{
lnk.linkStatus = TErrorList.out_of_client_memory;
if (trace) lnk.traceLink("sendLinkRequest", "no valid link id !");
return TErrorList.out_of_client_memory;
}
if (lnk.active && lnk.linkStatus == -1)
{ // this link is already being established
if (trace) lnk.traceLink("sendLinkRequest", "link is already being established !");
return 0;
}
lnk.lastLinkStatus = lnk.linkStatus;
if (lnk.lastLinkStatus == TErrorList.not_signalled) lnk.lastLinkStatus = 0;
if ((lnk.sub.mode & TMode.CM_GLOBAL) == TMode.CM_GLOBAL)
{ // a globals link !
if (trace) lnk.traceLink("sendLinkRequest", "link is a globals link !");
lnk.isGlobalsLink = true; // definitely turn this on !
if (lnk.dOutput == null) return TErrorList.invalid_parameter;
if (getGlobalsLinkThread() == null) startGlobalsListener();
if (lnk.srvAddr.fecAddr != null)
{ // the target globals server has a known address => join his multicast group
try
{
String[] mcaddr = initializer.getGCastAddress().split("\\.");
String[] ipaddr = lnk.srvAddr.fecAddr.fecHost.getHostAddress().split("\\.");
String ip = mcaddr[0] + "." + mcaddr[1] + "." + ipaddr[2] + "." + ipaddr[3];
InetAddress mcastGrp = InetAddress.getByName(ip);
if (numLinksInMulticastGroup(mcastGrp) == 0)
{
getGlobalsSocket().getSocket().joinGroup(mcastGrp);
}
lnk.setMulticastGroup(mcastGrp);
}
catch (Exception e)
{
e.printStackTrace();
MsgLog.log("sendLinkRequest","exception " + e.toString(),TErrorList.code_failure,e,1);
return TErrorList.code_failure;
}
}
lnk.linkStatus = -1; // pending
lnk.dOutput.blksin = lnk.dOutput.bytesin = 0;
lnk.dOutput.resetBuffersReady();
lnk.active = true;
if (trace) lnk.traceLink("sendLinkRequest", "request is now pending a response from server");
return 0;
}
if ((lnk.sub.mode & TMode.CM_MCAST) == TMode.CM_MCAST)
{ // a network subscription !
try
{ // join the right group
if (mtfThrd == null) startMulticastListener(sckRcvBufferSize,sckTimeToLive);
String[] mcaddr = initializer.getMCastAddress().split("\\.");
String[] ipaddr = lnk.srvAddr.fecAddr.fecHost.getHostAddress().split("\\.");
String ip = mcaddr[0] + "." + mcaddr[1] + "." + ipaddr[2] + "." + ipaddr[3];
InetAddress mcastGrp = InetAddress.getByName(ip);
if (numLinksInMulticastGroup(mcastGrp) == 0)
{ // no other links in this group so join !
getMulticastSocket().getSocket().joinGroup(mcastGrp);
}
lnk.setMulticastGroup(mcastGrp);
}
catch (IOException e)
{
MsgLog.log("sendLinkRequest","exception " + e.toString(),TErrorList.mcast_init_error,e,0);
return TErrorList.mcast_init_error;
}
}
if (useConnectedSockets) lnk.sub.mode |= TMode.CM_CONNECT;
byte[] hdrbytes, subbytes;
TFecEntry srv = lnk.srvAddr.fecAddr;
if (srv == null)
{
if (trace) lnk.traceLink("sendLinkRequest", "cannot resolve server address");
if (debugLevel > 0) DbgLog.log("sendLinkRequest","establish link : cannot resolve server address");
lnk.active = false;
return TErrorList.non_existent_fec;
}
if (lnk.srvAddr.fecAddr.getTineProtocol() == 0)
{ // somehow not yet set
lnk.srvAddr.fecAddr.setTineProtocol(TTransport.DEFAULT_PROTOCOL_LEVEL);
}
if (lnk.srvAddr.fecAddr.getTineProtocol() < 6 && !lnk.sub.isLegacy)
{
short mode = lnk.sub.mode;
lnk.setTineProtocol(lnk.srvAddr.fecAddr.getTineProtocol());
TContract c = lnk.sub.contract;
c.setLegacy(lnk);
lnk.sub = new TSubscription(c,lnk);
lnk.sub.mode = mode;
}
String usr = tineUserName;
if (lnk.sub.contract.eqmName.compareToIgnoreCase("DCSEQM") == 0)
{
if (doocsUserName != null && doocsUserName.length() > 0)
usr = doocsUserName;
}
int hdrSize = lnk.sub.isLegacy ? TSubscription.hdrSizeInBytesLegacy : TSubscription.hdrSizeInBytes;
int conSize = lnk.sub.isLegacy ? TContractP5.hdrSizeInBytes : TContract.hdrSizeInBytes;
lnk.dInput.resetCounters(lnk.getTineProtocol());
lnk.sub.resetCounters((short)lnk.dInput.blkid);
for (int n = 0; n < lnk.dInput.numblks; n++)
{
subbytes = lnk.sub.toByteArray(); // fixes lnk.sub.nextDataSizeInBytes
lnk.reqHdr.setUserName(usr);
lnk.reqHdr.setMsgSizeInBytes((short)(conSize + hdrSize + lnk.sub.nextDataSizeInBytes));
hdrbytes = lnk.reqHdr.toByteArray();
if (debugLevel > 0)
DbgLog.log("sendLinkRequest","trying to establish link " + lnk.linkId + "(" + (n + 1) + " of "
+ lnk.dInput.numblks + " " + lnk.reqHdr.getMsgSizeInBytes()+ " bytes)" + " : " + lnk.expName + " "
+ lnk.devName + " " + lnk.devProperty + " " + lnk.devTimeout + " msec");
try
{
if (sndLnkByteStream == null) sndLnkByteStream = new ByteArrayOutputStream(TTransport.UDP_BUFFER_SIZE);
ByteArrayOutputStream bs = sndLnkByteStream; bs.reset();
DataOutputStream ds = new DataOutputStream(bs);
ds.write(hdrbytes);
ds.write(subbytes);
if (lnk.sub.contract.dBuffer == null)
{
if (debugLevel > 0) DbgLog.log("sendLinkRequest","establish link : no address data returned");
lnk.active = false;
return TErrorList.non_existent_elem;
}
if (lnk.sub.contract.eqmName.length() == 0 || lnk.sub.msgSizeInBytes == 0)
{
if (debugLevel > 0) DbgLog.log("sendLinkRequest","establish link : header corrupt");
lnk.active = false;
return TErrorList.code_failure;
}
if (debugLevel > 0)
DbgLog.log("sendLinkRequest","send to : " + lnk.srvAddr.fecAddr.fecHost.getHostAddress() + ":"
+ lnk.srvAddr.fecAddr.fecPortOffset);
ds.write(lnk.sub.contract.toByteArray());
// package the input data payload ...
if (lnk.dInput.getArrayLength() > 0) ds.write(lnk.dInput.getDataBuffer(n));
// send it out ...
if (lnk.isInsideCallback && TMode.getBaseMode(lnk.sub.mode) == TMode.CM_SINGLE)
lnk.sub.mode &= ~(TMode.CM_CONNECT|TMode.CM_STREAM);
lnk.dOutput.blksin = 0;
lnk.dOutput.resetBuffersReady();
if (lnk.renewalMultiplier < 1) lnk.renewalMultiplier = 1;
int cc = sendLinkBytesToPeer(lnk, bs);
if (trace) lnk.traceLink("sendLinkRequest", "request bytes been sent to peer");
if (cc != 0) return cc;
}
catch (IOException e)
{
if (e instanceof NoRouteToHostException)
{
MsgLog.log("sendLinkRequest","no route to "+lnk.srvAddr.fecAddr.fecHost.getHostAddress(),TErrorList.net_write_error,e,0);
}
if (TMode.isConnected(lnk.getLinkAccessMode()))
{ // connection went down at the other end
removeTLinkBucket((TLinkBucket)lnk.tb,false);
}
else
{
e.printStackTrace();
}
if (debugLevel > 0) DbgLog.log("sendLinkRequest","establish link : IO Exception");
return TErrorList.net_write_error;
}
catch (Exception e)
{
e.printStackTrace();
MsgLog.log("sendLinkRequest", "unhandled exception: "+e.getMessage(), TErrorList.code_failure, e, 0);
return TErrorList.net_write_error;
}
}
if (debugLevel > 0) DbgLog.log("sendLinkRequest","establish link : success");
if (trace) lnk.traceLink("sendLinkRequest", "request has been sent");
lnk.active = true;
return 0;
} }
private byte[] sndLnkReqBuffer = new byte[TTransport.UDP_BUFFER_SIZE];
/*
* only packs multiple link requests to same FEC!
* no synchronous links; no query links; no globals links; no service links;
* no links with multiple input blocks; no connected sockets;
*
* @param lnks
* @return
*/
int sendLinkRequest(TLink[] lnks)
{ synchronized(lnkTblObject) {
if (lnks == null) return 0;
TLink reflnk = null;
TFecEntry srv = null;
for (TLink lnk : lnks)
{ // find the first in the list that needs to go out and use it as a reference
if (!lnk.needsToSendLinkRequest) continue;
if (lnk.active && lnk.linkStatus == -1) continue;
if (lnk.sub.mode == TMode.CM_REGISTER)
{
DbgLog.log("sendLinkRequest","mode CM_REGISTER not a valid remote access mode");
continue;
}
if (lnk.sub.contract == null || lnk.sub.contract.eqmName == null)
{
lnk.linkStatus = TErrorList.link_error;
continue;
}
srv = lnk.srvAddr.fecAddr;
if (srv == null)
{ // the server address is still unresolved ?!?
if (debugLevel > 0) DbgLog.log("sendLinkRequest","establish link : can't resolve server address");
lnk.active = false;
lnk.linkStatus = TErrorList.non_existent_fec;
continue;
}
reflnk = lnk;
break;
}
if (reflnk == null) return 0;
String usr = tineUserName;
if (reflnk.sub.contract.eqmName.compareToIgnoreCase("DCSEQM") == 0)
{
if (doocsUserName != null && doocsUserName.length() > 0)
usr = doocsUserName;
}
reflnk.reqHdr.setUserName(usr);
int numLinksNotSent = 0;
int sndLnkReqBufferPos = TReqHdr.hdrSizeInBytes;
int consize, datsize;
byte[] hdrbytes, subbytes, conbytes;
TLink clnk = null;
try
{
for (TLink lnk : lnks)
{
if (lnk.dInput.numblks > 1) continue;
if (lnk.linkStatus == TErrorList.link_blacklisted)
{
lnk.sub.linkLastTime = System.currentTimeMillis();
lnk.needsToSendLinkRequest = false;
continue;
}
if (lnk.linkId < 0)
{
lnk.linkStatus = TErrorList.out_of_client_memory;
lnk.needsToSendLinkRequest = false;
continue;
}
if (lnk.sub.contract.dBuffer == null)
{
if (debugLevel > 0) DbgLog.log("sendLinkRequest","establish link : no address data returned");
lnk.active = false;
lnk.linkStatus = TErrorList.non_existent_elem;
lnk.needsToSendLinkRequest = false;
continue;
}
if (lnk.sub.contract.eqmName.length() == 0 || lnk.sub.msgSizeInBytes == 0)
{
if (debugLevel > 0) DbgLog.log("sendLinkRequest","establish link : header corrupt");
lnk.active = false;
lnk.linkStatus = TErrorList.code_failure;
lnk.needsToSendLinkRequest = false;
continue;
}
if (lnk.active && lnk.linkStatus == -1)
{ // this link is already being established
lnk.needsToSendLinkRequest = false;
continue;
}
if (lnk.srvAddr.fecAddr != reflnk.srvAddr.fecAddr)
{
if (debugLevel > 3)
DbgLog.log("sendLinkRequest","skipping packed link "+lnk.getFullDeviceName()+" ("+TMode.toString(lnk.sub.mode)+") this pass");
numLinksNotSent++;
continue;
}
if (!lnk.getCriticalSection()) continue;
clnk = lnk;
lnk.needsToSendLinkRequest = false;
lnk.delayEstablishLink(false);
lnk.lastLinkStatus = lnk.linkStatus;
if (lnk.lastLinkStatus == TErrorList.not_signalled) lnk.lastLinkStatus = 0;
lnk.linkStatus = -1; // pending
if ((lnk.sub.mode & TMode.CM_MCAST) == TMode.CM_MCAST)
{ // a network subscription !
try
{ // join the right group
if (mtfThrd == null) startMulticastListener(sckRcvBufferSize,sckTimeToLive);
String[] mcaddr = initializer.getMCastAddress().split("\\.");
String[] ipaddr = lnk.srvAddr.fecAddr.fecHost.getHostAddress().split("\\.");
String ip = mcaddr[0] + "." + mcaddr[1] + "." + ipaddr[2] + "." + ipaddr[3];
InetAddress mcastGrp = InetAddress.getByName(ip);
if (numLinksInMulticastGroup(mcastGrp) == 0)
{ // no other links in this group so join !
getMulticastSocket().getSocket().joinGroup(mcastGrp);
}
lnk.setMulticastGroup(mcastGrp);
}
catch (IOException e)
{
MsgLog.log("sendLinkRequest","exception " + e.toString(),TErrorList.mcast_init_error,e,0);
lnk.linkStatus = TErrorList.mcast_init_error;
lnk.freeCriticalSection();
continue;
}
}
// if (useConnectedSockets) lnk.sub.mode |= TMode.CM_CONNECT;
if (lnk.srvAddr.fecAddr.getTineProtocol() == 0)
{ // somehow not yet set
lnk.srvAddr.fecAddr.setTineProtocol(TTransport.DEFAULT_PROTOCOL_LEVEL);
}
if (lnk.srvAddr.fecAddr.getTineProtocol() < 6 && !lnk.sub.isLegacy)
{
short mode = lnk.sub.mode;
lnk.setTineProtocol(lnk.srvAddr.fecAddr.getTineProtocol());
TContract c = lnk.sub.contract;
c.setLegacy(lnk);
lnk.sub = new TSubscription(c,lnk);
lnk.sub.mode = mode;
}
lnk.dInput.resetCounters(lnk.getTineProtocol());
lnk.sub.resetCounters((short)lnk.dInput.blkid);
if (debugLevel > 0)
DbgLog.log("sendLinkRequest","trying to establish link " + lnk.linkId + "(1 of "
+ lnk.dInput.numblks + " " + lnk.reqHdr.getMsgSizeInBytes()+ " bytes)" + " : " + lnk.expName + " "
+ lnk.devName + " " + lnk.devProperty + " " + lnk.devTimeout + " msec");
subbytes = lnk.sub.toByteArray();
conbytes = lnk.sub.contract.toByteArray();
datsize = lnk.dInput.getSizeInBytes();
consize = subbytes.length + conbytes.length + datsize;
if (sndLnkReqBufferPos + consize > TTransport.UDP_BUFFER_SIZE)
{ // send out what I've got
reflnk.reqHdr.setMsgSizeInBytes((short)(sndLnkReqBufferPos-TReqHdr.hdrSizeInBytes));
hdrbytes = reflnk.reqHdr.toByteArray();
System.arraycopy(hdrbytes, 0, sndLnkReqBuffer, 0, hdrbytes.length);
if (sndLnkByteStream == null) sndLnkByteStream = new ByteArrayOutputStream(TTransport.UDP_BUFFER_SIZE);
ByteArrayOutputStream bs = sndLnkByteStream; bs.reset();
DataOutputStream ds = new DataOutputStream(bs);
ds.write(sndLnkReqBuffer);
atp.dpOut = new DatagramPacket(bs.toByteArray(), bs.size(), srv.fecHost, initializer.getSrvPort()
+ srv.fecPortOffset);
atp.getSocket().send(atp.dpOut);
sndLnkReqBufferPos = TReqHdr.hdrSizeInBytes; // reset
}
System.arraycopy(subbytes, 0, sndLnkReqBuffer, sndLnkReqBufferPos, subbytes.length);
sndLnkReqBufferPos += subbytes.length;
System.arraycopy(conbytes, 0, sndLnkReqBuffer, sndLnkReqBufferPos, conbytes.length);
sndLnkReqBufferPos += conbytes.length;
if (lnk.dInput.getArrayLength() > 0)
{
System.arraycopy(lnk.dInput.getDataBuffer(0), 0, sndLnkReqBuffer, sndLnkReqBufferPos, datsize);
sndLnkReqBufferPos += datsize;
}
lnk.dOutput.blksin = lnk.dOutput.bytesin = 0;
lnk.dOutput.resetBuffersReady();
if (debugLevel > 0) DbgLog.log("sendLinkRequest","establish link : success");
if (lnk.sub.mode != TMode.CM_CANCEL) lnk.active = true;
lnk.freeCriticalSection();
}
clnk = null;
if (sndLnkReqBufferPos > TReqHdr.hdrSizeInBytes)
{ // something left to send
reflnk.reqHdr.setMsgSizeInBytes((short)(sndLnkReqBufferPos-TReqHdr.hdrSizeInBytes));
hdrbytes = reflnk.reqHdr.toByteArray();
System.arraycopy(hdrbytes, 0, sndLnkReqBuffer, 0, hdrbytes.length);
if (sndLnkByteStream == null) sndLnkByteStream = new ByteArrayOutputStream(TTransport.UDP_BUFFER_SIZE);
ByteArrayOutputStream bs = sndLnkByteStream; bs.reset();
DataOutputStream ds = new DataOutputStream(bs);
ds.write(sndLnkReqBuffer);
atp.dpOut = new DatagramPacket(bs.toByteArray(), bs.size(), srv.fecHost, initializer.getSrvPort()
+ srv.fecPortOffset);
atp.getSocket().send(atp.dpOut);
sndLnkReqBufferPos = TReqHdr.hdrSizeInBytes; // reset
}
}
catch (IOException e)
{
e.printStackTrace();
if (debugLevel > 0) DbgLog.log("sendLinkRequest","establish link : IO Exception");
reflnk.linkStatus = TErrorList.net_write_error;
}
catch (Exception e)
{
e.printStackTrace();
MsgLog.log("sendLinkRequest", "unhandled exception: "+e.getMessage(), TErrorList.code_failure, e, 0);
}
if (clnk != null) clnk.freeCriticalSection(); // in case we're here via an exception
if (debugLevel > 3) DbgLog.log("sendLinkRequest","number of packed links not sent this pass : "+numLinksNotSent);
return numLinksNotSent;
} }
private static final int link_not_identified = 999999999;
public TLink findLink(InetAddress inetAddr,int port)
{
return findLink(link_not_identified,inetAddr,port);
}
public TLink findLink(int linkid, InetAddress inetAddr,int port)
{
InetAddress ia;
TFecEntry fec;
for (int i = 0; i < numberTLinksInTable; i++) /* cross reference */
{
if (linkTable[i] == null || linkTable[i] == tNullLink) continue;
if (linkTable[i].getTineProtocol() < TTransport.DEFAULT_PROTOCOL_LEVEL) continue;
if ((fec=linkTable[i].srvAddr.fecAddr) == null) continue;
if (linkid != link_not_identified && linkTable[i].srvId != linkid) continue;
ia = fec.fecHost;
if (ia.getHostAddress().compareTo(inetAddr.getHostAddress()) != 0) continue;
if (port != initializer.getSrvPort() + fec.fecPortOffset) continue;
return linkTable[i];
}
return null;
}
public int findTLink(TLink link)
{
for (int i = 0; i < numberTLinksInTable; i++)
{
if (linkTable[i] == link) return i;
}
return -1;
}
public TLink findTLink(int linkid, int linkstarttime)
{
if (linkstarttime == TFecEntry.BCAST_ID) /* BCAST or MCAST contract */
{ // should not land here!
DbgLog.log("findTLink","incoming multicast link id not expected");
for (int i = 0; i < numberTLinksInTable; i++) /* cross reference */
{
if (linkTable[i] == null || linkTable[i] == tNullLink) continue;
if (linkTable[i].srvId != linkid) continue;
return linkTable[i];
}
return null;
}
if (linkstarttime == TFecEntry.ENS_ID)
{
if (linkTable[0] != null && linkTable[0].sub.id != linkid)
{
return null;
}
linkTable[0].removeOnClose = false; // how many times do I have to set this ?
return linkTable[0];
}
if (debugLevel > 2)
{
DbgLog.log("findTLink","find incoming link id "+linkid+" start time "+
linkstarttime+" among "+numberTLinksInTable+" registered links");
}
if (linkid < 0 || linkid >= numberTLinksInTable) return null;
if (linkTable[linkid] == null || linkTable[linkid].sub == null) return null;
if (debugLevel > 2) DbgLog.log("findTLink","link table id " + linkid +
" : start time " + linkTable[linkid].sub.starttime);
if (linkTable[linkid].sub.starttime != linkstarttime) return null;
if (debugLevel > 1)
DbgLog.log("findTLink","returning link "+linkid+" "+linkTable[linkid].getFullDeviceNameAndProperty());
return linkTable[linkid];
}
public TLink findTLink(InetAddress gaddr, String context, String keyword)
{ // method used for finding globals links
keyword = keyword.trim();
if (debugLevel > 2)
DbgLog.log("findTLink","looking for global link "+keyword+" in context "+context+" among "+numberTLinksInTable
+ " registered links");
for (int i = 0; i < numberTLinksInTable; i++)
{
if (linkTable[i] == null || linkTable[i] == tNullLink) continue;
if (linkTable[i].sub == null) continue;
if (!TMode.isGlobal(linkTable[i].sub.mode))
{
if (debugLevel > 4) DbgLog.log("findTLink",linkTable[i].devProperty + " is not a global");
continue;
}
if (gaddr != null)
{ // if given, make sure it's coming from the correct source
if (linkTable[i].expName == null ||
linkTable[i].srvAddr == null ||
linkTable[i].srvAddr.fecAddr == null ||
linkTable[i].srvAddr.fecAddr.fecHost == null) continue;
if (!linkTable[i].srvAddr.fecAddr.fecHost.equals(gaddr)) continue;
}
if (context != null && linkTable[i].getContext().compareToIgnoreCase(context) != 0) continue;
if (debugLevel > 2)
DbgLog.log("findTLink","Compare " + keyword + " against " + linkTable[i].devProperty);
if (linkTable[i].devProperty == null) continue;
if (keyword.compareToIgnoreCase(linkTable[i].devProperty) == 0) // found it
{
if (debugLevel > 1) DbgLog.log("findTLink","returning link "+i+" : "+linkTable[i].getFullDeviceName());
return linkTable[i];
}
}
if (debugLevel > 2) DbgLog.log("findTLink",keyword+" not required by application : data discarded");
return null;
}
public TLink findTLink(InetAddress gaddr, String keyword)
{ // method used for finding globals links
return findTLink(gaddr,null,keyword);
}
/**
* Insert the method's description here. Creation date: (8/24/01 3:51:37 PM)
*
* @return de.desy.tine.client.TLinkFactory
*/
public static synchronized TLinkFactory getInstance()
{
if (instance == null) instance = new TLinkFactory();
return instance;
}
/*
* Put a new TLink in the link table Creation date: (8/17/01 5:59:27 PM)
*
* @return TLink
*/
public void activateLink(TLink link)
{
linkTable[link.linkId] = link;
if (debugLevel > 0)
DbgLog.log("activateLink","creating TLink " + linkTable[link.linkId] + " (" + link.linkId + ")");
}
/*
* Put a new TLink in the link table Creation date: (8/17/01 5:59:27 PM)
*
* @return TLink
*/
public int registerLink(TLink link)
{
int i;
if (link.expName.startsWith("ENS") &&
(link.cntName.startsWith("DEFAULT") || link.cntName.length() == 0))
{
i = adjustLinkTable(link,adjustLinkTableAdd);
}
else
{
i = adjustLinkTable(tNullLink,adjustLinkTableAdd);
}
return i;
}
/**
* Remove a TLink from the link table Removes a TLink from the link
* table by setting the entry explicitly to null. If the link is a TCP/IP link
* then the termination flag is reset to false in order to give the
* terminateBucket thread a chance to clean up the connection.
*/
protected void removeTLink(TLink lnk)
{
adjustLinkTable(lnk, adjustLinkTableRemove);
}
/*
* called by TEquipmentModuleFactory during a general server shutdown
*/
public void shutdown()
{
MsgLog.log("TLinkFactory.shutdown", "shutting down",0,null,0);
active = false;
if (atp != null) atp.shutdown();
if (stp != null) stp.shutdown();
if (qtp != null) qtp.shutdown();
if (nmtp != null) nmtp.shutdown();
if (gtp != null) gtp.shutdown();
}
public int setDebugLevel(int level)
{
return setOutputDebugLevel(level);
}
public int getDebugLevel()
{
return debugLevel;
}
public static int setOutputDebugLevel(int level)
{
if (gIsRunningAsServer) TEquipmentModuleFactory.setDebugLevel(level);
MsgLog.setDebugLevel(level);
TLinkFactory.debugLevel = level;
if (!java.awt.GraphicsEnvironment.isHeadless() && level >= 0)
{
try
{
TConsole tc = TConsole.getInstance();
if (!TCommandList.isExecuting() && !tc.isShowing())
{
if (level > 0) tc.show();
}
else
{
tc.setDebugLevel(level);
}
}
catch (Exception e)
{ // maybe there's no way to make GUI components?
e.printStackTrace();
System.out.println("cannot instantiate the TConsole !");
}
}
return TLinkFactory.debugLevel;
}
public static int getOutputDebugLevel()
{
return TLinkFactory.debugLevel;
}
}