package de.desy.tine.histUtils;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;
import de.desy.tine.addrUtils.TSrvEntry;
import de.desy.tine.client.TLink;
import de.desy.tine.dataUtils.*;
import de.desy.tine.definitions.*;
import de.desy.tine.exceptions.UnresolvedAddressException;
import de.desy.tine.queryUtils.TPropertyQuery;
import de.desy.tine.queryUtils.TQuery;
import de.desy.tine.server.histories.THistoryRecordStruct;
import de.desy.tine.server.histories.THistorySpecification;
import de.desy.tine.server.logger.DbgLog;
import de.desy.tine.server.logger.MsgLog;
import de.desy.tine.types.*;
import de.desy.tine.stringUtils.*;
/**
* THistory is a utility class with numerous static methods for access
* archive data from either the central archive system of the local
* history subsystems of targeted servers.
*
* @author duval
*/
public final class THistory
{
private static final int HEARTBEAT = 60 * 15;
private static final int EXTENSION_LIMIT = 15*60;
private static final int MAX_HSTCFG_SIZE = 500;
private static HstCfg[] cfgs = new HstCfg[MAX_HSTCFG_SIZE];
private static McaCfg[] mcacfgs = new McaCfg[MAX_HSTCFG_SIZE];
private static PrfCfg[] prfcfgs = new PrfCfg[MAX_HSTCFG_SIZE];
private static HstView[] views = new HstView[MAX_HSTCFG_SIZE];
private static boolean isInitialized = false;
private static void initCfgs()
{
if (isInitialized) return;
for (int i=0; i<MAX_HSTCFG_SIZE; i++)
{
cfgs[i] = new HstCfg();
mcacfgs[i] = new McaCfg();
prfcfgs[i] = new PrfCfg();
views[i] = new HstView();
}
isInitialized = true;
}
private static boolean isCentralArchiveServer(String server)
{
return server.endsWith("HISTORY");
}
private static boolean isCentralArchiver(String server)
{
return server.endsWith("ARCHIVER");
}
private static String getQueryPropertyRoot(String property)
{
int slen = property.length();
if (property.endsWith(".HIST") || property.endsWith(".ARCH"))
return property.substring(0, slen-5);
if (property.endsWith(".HST") || property.endsWith(".ARC"))
return property.substring(0, slen-4);
if (property.endsWith(".AR"))
return property.substring(0, slen-3);
return property;
}
private static boolean isScheduledProperty(String property)
{
int idx = property.lastIndexOf('.');
if (idx < 0) return false;
String dec = property.substring(idx+1);
if (dec == null) return false;
return dec.toUpperCase().startsWith("SCH");
}
private static boolean isArchiveQueryProperty(String property)
{
if (property.endsWith(".HIST")) return true;
if (property.endsWith(".HST")) return true;
if (property.endsWith(".ARCH")) return true;
if (property.endsWith(".ARC")) return true;
if (property.endsWith(".AR")) return true;
return false;
}
private static synchronized int getArchivedNumPointsInInterval(String context,String server, String property, String device, double start, double stop,int timeout)
{
int cc = 0;
int[] startstop = new int[2];
int[] npts = new int[1];
TDataType dout, din;
if (server == null && context == null) return TErrorList.argument_list_error;
if (context == null) context = "DEFAULT";
if (server == null) server = "HISTORY"; // assume the standard central archive server for the given context
startstop[0] = (int)start;
startstop[1] = (int)stop;
din = new TDataType(startstop);
dout = new TDataType(npts);
if (isCentralArchiver(server))
{ // trap a potential redirection problem here:
if (device.compareToIgnoreCase("keyword") == 0) device = "#0";
}
String dname = new String("/" + context + "/" + server + "/" + device);
String pname = new String(property);
if (!isCentralArchiveServer(server))
{ // not a call to a central archive server
if (!isArchiveQueryProperty(property))
pname = pname + ".HIST"; // meta extension not given, try this ...
}
try
{
TLink tl = new TLink(dname,pname,dout,din,TAccess.CA_READ);
cc = tl.execute(timeout, true);
tl.close();
}
catch (UnresolvedAddressException e)
{
cc = TErrorList.address_unresolved;
}
return cc > 0 ? -cc : npts[0];
}
public static String[] getArchiveSource(String context,String server, String property, String device,int timeout)
{
String[] src = null;
int cc = 0;
TDataType dout;
if (server == null && context == null) return src;
if (context == null) context = "DEFAULT";
if (server == null) server = "HISTORY"; // assume the standard central archive server for the given context
if (srcTbl != null)
{
String value = device+"["+property+"]";
if (srcTbl.containsValue(value))
{
Set<String> kset = srcTbl.keySet();
Iterator<String> i = kset.iterator();
String key;
while (i.hasNext())
{
key = i.next();
if (srcTbl.get(key).compareToIgnoreCase(value) == 0)
return new String[]{key};
}
}
}
String dname = new String("/" + context + "/" + server + "/" + property);
try
{
if (isCentralArchiveServer(server) || isCentralArchiver(server))
{ // call to a central archive server
String[] keysrcs = new String[100];
dout = new TDataType(keysrcs);
TLink tl = new TLink(dname,"KEYWORD.SOURCE",dout,null,TAccess.CA_READ);
cc = tl.executeAndClose(timeout);
if (cc == 0)
{
int len =dout.getCompletionLength();
if (len < 100) keysrcs = Arrays.copyOf(keysrcs, len);
src = keysrcs;
if (srcTbl != null && selectedContext != null &&
context.compareToIgnoreCase(selectedContext) == 0)
{ // if there's a hash table going, add to it
String dev;
String key = "keyword["+property+"]";
String[] devs = null;
if (keysrcs.length > 1)
{
devs = TQuery.getDeviceNames(context, server, property);
}
for (int k=0; k<keysrcs.length; k++)
{ // key is the src string (per device)
if (keysrcs[k] == null) break;
if (keysrcs.length > 1)
{
dev = (devs == null || k >= devs.length) ? "#"+k : devs[k];
key = dev+"["+property+"]";
}
srcTbl.put(keysrcs[k],key);
}
}
}
}
else
{
src = new String[]{"/"+context+"/"+server+"/"+device+"["+property+"]"};
}
}
catch (UnresolvedAddressException e)
{
cc = TErrorList.address_unresolved;
}
if (cc != 0) MsgLog.log("getArchiveSource", TErrorList.toString(cc),cc,null,1);
return src;
}
public static synchronized FLTFLT getToleranceOverInterval(String context,String server, String property, double start, double stop,int timeout)
{
int cc = 0;
int[] startstop = new int[2];
TDataType dout, din;
FLTFLT tols = new FLTFLT(0,0);
if (server == null && context == null) return tols;
if (context == null) context = "DEFAULT";
if (server == null) server = "HISTORY"; // assume the standard central archive server for the given context
startstop[0] = (int)start;
startstop[1] = (int)stop;
String dname = new String("/" + context + "/" + server + "/" + property);
try
{
if (isCentralArchiveServer(server))
{ // call to a central archive server
FLTFLT[] dtols = new FLTFLT[1];
dtols[0] = tols;
din = new TDataType(startstop);
dout = new TDataType(dtols);
TLink tl = new TLink(dname,"KEYWORD.TOLERANCE",dout,din,TAccess.CA_READ);
cc = tl.executeAndClose(timeout);
}
else
{
THistoryRecordStruct[] hrs = new THistoryRecordStruct[1];
hrs[0] = new THistoryRecordStruct();
din = new TDataType(property);
dout = new TDataType(hrs);
TLink tl = new TLink(dname,"HISTORIES",dout,din,TAccess.CA_READ);
cc = tl.executeAndClose(timeout);
if (cc == 0)
{
tols.f1val = hrs[0].getAbsoluteTolerance();
tols.f2val = hrs[0].getPercentTolerance();
}
}
}
catch (UnresolvedAddressException e)
{
cc = TErrorList.address_unresolved;
}
if (cc != 0) MsgLog.log("getToleranceOverInterval", TErrorList.toString(cc),cc,null,1);
return tols;
}
public static double[] getToleratedUpperValues(double[] data,float tolAbsolute,float tolRelative)
{
if (data == null) return null;
double[] d = new double[data.length];
for (int i=0; i<data.length; i++)
{
d[i] = data[i]*(1.0 + tolRelative) + tolAbsolute;
}
return d;
}
public static double[] getToleratedLowerValues(double[] data,float tolAbsolute,float tolRelative)
{
if (data == null) return null;
double[] d = new double[data.length];
for (int i=0; i<data.length; i++)
{
d[i] = data[i]*(1.0 - tolRelative) - tolAbsolute;
}
return d;
}
public static int getArchivedStatus(String context,String server, String property, String device, double start, double stop,NAME32DBLDBL[] data)
{
return getStatusArray(context,server,property,device,start,stop,data,1000);
}
public static int getArchivedStatus(String context,String server, String property, String device, double start, double stop,NAME32DBLDBL[] data,int timeout)
{
return getStatusArray(context,server,property,device,start,stop,data,timeout);
}
private static synchronized int getStatusArray(String context,String server, String property, String device, double start, double stop, TCompoundDataObject[] data, int timeout)
{
if (context == null || property == null || data == null) return TErrorList.invalid_parameter;
if (data.length < 1) return -TErrorList.dimension_error;
if (timeout < 100) timeout = 100;
int idx;
String s1 = server;
String p1 = property;
if (s1 == null) s1 = "HISTORY";
if ((idx=property.indexOf(".HIST")) >= 0 ||
(idx=property.indexOf(".HST")) >= 0 ||
(idx=property.indexOf(".AR")) >= 0)
{ // passed with .HIST appended, remove it!
property = property.substring(0, idx);
}
if (!isCentralArchiveServer(s1))
{ // a specific server was passed
p1 = property + ".ARCH"; // redirect to same channel at the central archiver
}
if (!(data instanceof NAME32DBLDBL[]))
{ // CF_NAME32DBLDBL and ONLY CF_NAME32DBLDBL
return -TErrorList.illegal_format;
}
int nret = getArchivedDataArray(context,s1,p1,device,0,start,stop,data,timeout);
if (nret == -TErrorList.illegal_format) nret = 0; // old archive server
return nret;
}
public static synchronized int getAnnotationTimes(String context, String property, double start, double stop, double[] data, int timeout)
{
return getAnnotationTimes(context,property,start,stop,data,null,timeout);
}
public static synchronized int getAnnotationTimes(String context, String property, double start, double stop, double[] data, boolean[] isActive, int timeout)
{
if (context == null || property == null || data == null) return -TErrorList.invalid_parameter;
if (data.length < 1) return -TErrorList.dimension_error;
if (timeout < 100) timeout = 100;
INTINT[] iidata = null;
int[] startstop = new int[2];
startstop[0] = (int)start;
startstop[1] = (int)stop;
TDataType din, dout;
if (startstop[0] == 0 && startstop[1] == 0)
{
din = new TDataType();
}
else
{
din = new TDataType(startstop);
}
String dname = new String("/"+context+"/HISTORY/"+property);
if (isActive != null && isActive.length >= data.length)
{
iidata = new INTINT[data.length];
dout = new TDataType(iidata);
}
else
{
isActive = null;
dout = new TDataType(data);
}
TLink tl = new TLink(dname,"RECORD.CMTS",dout,din,TAccess.CA_READ);
int cc = tl.executeAndClose(timeout);
if (cc != 0) return -cc;
int n = dout.getCompletionLength();
if (isActive != null)
{
for (int i=0; i<n; i++)
{
data[i] = iidata[i].i1val;
isActive[i] = iidata[i].i2val != 0;
}
}
else
{
if (n > 0) Arrays.sort(data,0,n);
}
return n;
}
public static synchronized int getAnnotation(String context, String property, double target, String[] data, int timeout)
{
if (context == null || property == null || data == null) return TErrorList.invalid_parameter;
if (data.length < 1) return TErrorList.dimension_error;
if (timeout < 100) timeout = 100;
TDataType dout;
char[] cmt = new char[1024];
dout = new TDataType(cmt);
String dname = new String("/"+context+"/HISTORY/"+property+"@"+(int)target);
TLink tl = new TLink(dname,"RECORD.CMT",dout,null,TAccess.CA_READ);
int cc = tl.executeAndClose(timeout);
if (cc != 0) return cc;
int len = dout.getCompletionLength();
data[0] = new String(cmt,0,len);
return 0;
}
/**
* Annotates the designated context in the central archive at the current
* time.
*
* @param context is the context of the Central Archive Server
* @param text is the desired annotation text
*
* @return 0 upon success or a TINE error code
*/
public static synchronized int setAnnotation(String context, String text)
{
return setAnnotation(context,"State",0,text,false,1000);
}
/**
* Annotates the designated record property in the central archive at the current
* time.
*
* @param context is the context of the Central Archive Server
* @param property is the targeted record keyword name
* @param text is the desired annotation text
*
* @return 0 upon success or a TINE error code
*/
public static synchronized int setAnnotation(String context, String property, String text)
{
return setAnnotation(context,property,0,text,false,1000);
}
/**
* Annotates the designated record property in the central archive
*
* @param context is the context of the Central Archive Server
* @param property is the targeted record keyword name
* @param targetTime is the desired annotation time (if <= 0 then the
* current time will be used)
* @param text is the desired annotation text
* @param timeout is the allowed duration of the annotation call before issuing
* a timeout message.
*
* @return 0 upon success or a TINE error code
*/
public static synchronized int setAnnotation(String context, String property, double targetTime, String text, int timeout)
{
return setAnnotation(context,property,targetTime,text,false,timeout);
}
/**
* Annotates the designated record property in the central archive
*
* @param context is the context of the Central Archive Server
* @param property is the targeted record keyword name
* @param targetTime is the desired annotation time (if <= 0 then the
* current time will be used)
* @param text is the desired annotation text
* @param keepAlive if 'true' this will flag the annotation as 'active'
* (i.e. valid until cleared by the next annotation)
* @param timeout is the allowed duration of the annotation call before issuing
* a timeout message.
*
* @return 0 upon success or a TINE error code
*/
public static synchronized int setAnnotation(String context, String property, double targetTime, String text, boolean keepAlive, int timeout)
{
if (context == null || property == null || text == null) return TErrorList.invalid_parameter;
if (timeout < 100) timeout = 100;
if (targetTime <= 0) targetTime = TDataTime.getDataTimeStamp();
TDataType din = null;
if (text != null && text.length() > 0)
{
din = new TDataType(text.toCharArray());
}
String keepString = keepAlive ? "[KEEPALIVE]" : "";
String dname = new String("/"+context+"/HISTORY/"+property+"@"+(int)targetTime+keepString);
TLink tl = new TLink(dname,"RECORD.CMT",null,din,TAccess.CA_WRITE);
return tl.executeAndClose(timeout);
}
private static String lastDataKey = null;
private static NAME32DBLDBL[] ndd = null;
private static double[] ats = null;
private static boolean[] atsActive = null;
private static synchronized int getDataArray(String context,String server, String property, String device, int index, double start, double stop, TCompoundDataObject[] data, THistorySource src, int timeout)
{
int idx, cc = 0;
HstSrc[] srvs = new HstSrc[2];
String s1 = server;
String p1 = property;
if (s1 == null) s1 = "HISTORY";
if ((idx=property.indexOf(".HIST")) >= 0 ||
(idx=property.indexOf(".HST")) >= 0 ||
(idx=property.indexOf(".AR")) >= 0)
{ // passed with .HIST appended, remove it!
property = property.substring(0, idx);
}
String s2 = s1; // server 2nd source
if (!isCentralArchiveServer(s1))
{ // a specific server was passed
p1 = property + ".ARCH"; // redirect to same channel at the central archiver
}
else
{ // 2nd source must redirect back to find the target server's local histories
s2 = "ARCHIVER";
}
double npstart, npstop;
boolean extendedRange = (src != null && src.hasExtendedTimeRange());
npstart = extendedRange ? start + HEARTBEAT*2 : start;
npstop = extendedRange ? stop - HEARTBEAT*2 : stop;
int npts1 = getArchivedNumPointsInInterval(context, s1, p1, device, npstart, npstop, 500);
if (npts1 < 0)
{ // a problem with this entry
npts1 = 0;
lastDataKey = null;
ndd = null;
ats = null;
atsActive = null;
}
else
{ // central archive is alive and knows about the record
String thisDataKey = "/"+context+"["+property+"]"+start+"->"+stop;
if (lastDataKey == null || thisDataKey.compareToIgnoreCase(lastDataKey) != 0)
{
int ndays = (int)((stop - start)) / 86400;
if (ndays < 1) ndays = 1;
ndd = new NAME32DBLDBL[ndays*100];
int nr = getArchivedStatus(context, "HISTORY", property, device, start, stop, ndd, timeout);
ndd = nr <= 0 ? null : Arrays.copyOf(ndd, nr);
ats = new double[ndays*10];
atsActive = new boolean[ndays*10];
nr = getAnnotationTimes(context, property, start, stop, ats, atsActive, timeout);
ats = nr <= 0 ? null : Arrays.copyOf(ats, nr);
atsActive = nr <= 0 ? null : Arrays.copyOf(atsActive, nr);
lastDataKey = thisDataKey;
}
}
srvs[0] = new HstSrc("Central Archive",s1,npts1);
String p2 = property + ".HIST";
int npts2 = getArchivedNumPointsInInterval(context, s2, p2, device, npstart, npstop, 500);
if (npts2 < 0)
{ // a problem with this entry
if (npts2 == -TErrorList.un_allocated)
{
String[] hists = getArchivedProperties(context,s2);
if (hists != null)
{ // there are histories available ....
if (isScheduledProperty(property))
{ // look for unscheduled alternative
for (String h : hists)
{
if (property.startsWith(h))
{
p2 = h+".HIST";
npts2 = getArchivedNumPointsInInterval(context, s2, p2, device, npstart, npstop, 500);
break;
}
}
}
else
{ // look for scheduled alternative
for (String h : hists)
{
if (isScheduledProperty(h))
{
if (h.startsWith(property))
{
p2 = h+".HIST";
npts2 = getArchivedNumPointsInInterval(context, s2, p2, device, npstart, npstop, 500);
break;
}
}
}
}
}
}
if (npts2 < 0) npts2 = 0;
}
srvs[1] = new HstSrc("Local History",s2,npts2);
boolean done = false;
int nret = 0;
if (npts1 > 500 || npts1 > npts2)
{ // central archive has 'enough' points or at least more than the local history
nret = getArchivedDataArray(context,s1,p1,device,index,start,stop,data,timeout);
if (nret > 0)
{ // everything's okay
srvs[0].setAsDefault(true);
srvs[0].setNumberReturned(nret);
done = true;
}
else
{
cc = -nret;
}
}
if (!done && npts2 > 0)
{ // too few (or no) points upstairs, so try the local history ...
nret = getArchivedDataArray(context,s2,p2,device,index,start,stop,data,timeout);
srvs[1].setAsDefault(true);
if (nret > 0)
{
srvs[1].setNumberReturned(nret);
done = true;
}
else
{
cc = -nret;
}
if (cc != 0)
{
if (npts1 > 0)
{ // would have been a nice place for a 'goto' ....
nret = getArchivedDataArray(context,s1,p1,device,index,start,stop,data,timeout);
if (nret > 0)
{ // everything's okay
srvs[1].setAsDefault(false);
srvs[0].setAsDefault(true);
srvs[0].setNumberReturned(nret);
done = true;
}
}
}
}
if (!done && npts2 == 0 &&
!(data instanceof INTFLTINT[]) &&
!isCentralArchiveServer(server) &&
!isCentralArchiver(server))
{ // last desperate attempt (possible legacy doocs server ?)
int ifi_len = data.length;
if (ifi_len < 2000) ifi_len = 2000;
INTFLTINT[] ifi = new INTFLTINT[ifi_len];
int rst = 1, dn = 0, n = 0;
double interim = 0;
while (start < stop)
{
nret = getArchivedDataArray(context,s2,p2,device,index,start,stop,ifi,timeout);
if (nret > 1)
{
if (dn == 0)
{
dn = (ifi[nret-1].i1val-(int)start);
if (dn <= 0) dn = 1;
rst = (int)(stop-start) / dn;
if (rst < 1) rst = 1;
}
for (int i=0; n<data.length && i<nret; i += rst)
{
if (ifi[i] == null)
{
nret = i;
break;
}
if (data instanceof FLTINT[])
((FLTINT[])data)[n] = new FLTINT(ifi[i].fval,ifi[i].i1val);
else if (data instanceof DBLDBL[])
((DBLDBL[])data)[n] = new DBLDBL((double)ifi[i].fval,(double)ifi[i].i1val);
n++;
}
interim = (double)(ifi[nret-1].i1val + 1);
if (interim <= start) break;
start = interim;
done = true;
if (rst == 1) break;
}
else
{
break;
}
}
srvs[1].setAsDefault(true);
srvs[1].setNumberPoints(n);
srvs[1].setNumberReturned(n);
}
if (src != null)
{ // was passed, fill it in ...
src.CentralArchive = srvs[0];
src.LocalHistory = srvs[1];
src.setNumberOfPointsReturned(nret);
src.setStatusList(ndd);
src.setAnnotationTimes(ats);
src.setAnnotationActive(atsActive);
}
return cc;
}
private static synchronized int getArchivedDataArray(String context,String server, String property, String device, int index, double start, double stop, TCompoundDataObject[] data, int timeout)
{
return getArchivedDataArray(context,server,property,device,index,0,start,stop,data,timeout);
}
private static synchronized int getArchivedDataArray(String context,String server, String property, String device, int index, int sample, double start, double stop, TCompoundDataObject[] data, int timeout)
{
int cc = 0;
int[] startstop = new int[4];
TDataType dout, din;
if (server == null && context == null) return -TErrorList.argument_list_error;
if (data == null) return -TErrorList.argument_list_error;
if (context == null) context = "DEFAULT";
if (server == null) server = "HISTORY"; // assume the standard central archive server for the given context
if (timeout < 100) timeout = 100;
startstop[0] = (int)start;
startstop[1] = (int)stop;
startstop[2] = index;
startstop[3] = sample;
if (startstop[0] == 0 && startstop[1] == 0)
{
din = new TDataType();
}
else if (data instanceof INTFLTINT[])
{
WINDOW[] twnd = new WINDOW[1];
twnd[0] = new WINDOW(startstop[0],startstop[1],0,0);
din = new TDataType(twnd);
}
else
{
din = new TDataType(startstop);
}
dout = new TDataType(data);
if (isCentralArchiver(server))
{ // trap a potential redirection problem here:
if (device.compareToIgnoreCase("keyword") == 0) device = "#0";
}
String dname = new String("/" + context + "/" + server + "/" + device);
String pname = new String(property);
String rname = getQueryPropertyRoot(property);
boolean tryAlternateProperty = false;
if (!isCentralArchiveServer(server))
{ // not a call to a central archive server
tryAlternateProperty = true;
if (!isArchiveQueryProperty(property))
pname = pname + ".HIST"; // meta extension not given, try this ...
}
TLink tl = new TLink(dname,pname,dout,din,TAccess.CA_READ);
cc = tl.executeAndClose(timeout);
if (cc == TErrorList.un_allocated && tryAlternateProperty)
{
String[] hists = getArchivedProperties(context,server);
if (hists != null)
{ // there are histories available ....
if (isScheduledProperty(rname))
{ // look for unscheduled alternative
for (String h : hists)
{
if (rname.startsWith(h))
{
pname = h+".HIST";
tl = new TLink(dname,pname,dout,din,TAccess.CA_READ);
cc = tl.executeAndClose(timeout);
break;
}
}
}
else
{ // look for scheduled alternative
for (String h : hists)
{
if (isScheduledProperty(h))
{
if (h.startsWith(rname))
{
pname = h+".HIST";
tl = new TLink(dname,pname,dout,din,TAccess.CA_READ);
cc = tl.executeAndClose(timeout);
break;
}
}
}
}
}
}
if (cc != 0 && isCentralArchiver(server))
{ // special 2nd chance !
if (isArchiveQueryProperty(property))
{
pname = rname + ".ARCH";
}
else
{
pname = new String(property) + ".ARCH";
}
tl = new TLink(dname,pname,dout,din,TAccess.CA_READ);
cc = tl.executeAndClose(timeout);
}
return cc == 0 ? dout.getCompletionLength() : -cc;
}
private static int getArchivedDataArray(String context,String server, String property, String device, int index, double start, double stop,TCompoundDataObject[] data)
{
return getArchivedDataArray(context,server,property,device,index,start,stop,data,2000);
}
private static synchronized int getArchivedDataSnapshot(String context,String server, String property, String device, double[] targetTime,float[] data)
{
int cc = 0;
double[] dstartstop = new double[2];
TDataType dout, din;
if (server == null && context == null) return TErrorList.argument_list_error;
if (targetTime == null || data == null) return TErrorList.argument_list_error;
if (context == null) context = "DEFAULT";
if (server == null) server = "HISTORY"; // assume the standard central archive server for the given context
dstartstop[0] = targetTime[0];
dstartstop[1] = targetTime[0];
din = new TDataType(dstartstop);
dout = new TDataType(data);
String dname = new String("/" + context + "/" + server + "/" + device);
String[] pname = new String[2];
pname[0] = new String(property);
int ntries = 1;
if (!server.endsWith("HISTORY"))
{ // not a call to a central archive server
if (!isArchiveQueryProperty(property))
{ // meta extension not given, try this ...
pname[0] = property + ".HIST";
pname[1] = property + ".ARCH";
ntries = 2;
}
}
for (int i=0; i<ntries; i++)
{
TLink tl = new TLink(dname,pname[i],dout,din,TAccess.CA_READ);
cc = tl.execute(2000, true);
targetTime[0] = tl.getLastDataTimeStamp();
tl.close();
if (cc == 0 && dout.getCompletionLength() > 0) break;
}
return cc;
}
private static synchronized int getArchivedDataSnapshot(String context,String server, String property, String device, double[] targetTime,String[] data)
{
int cc = 0;
double[] dstartstop = new double[2];
TDataType dout, din;
if (server == null && context == null) return TErrorList.argument_list_error;
if (targetTime == null || data == null) return TErrorList.argument_list_error;
if (context == null) context = "DEFAULT";
if (server == null) server = "HISTORY"; // assume the standard central archive server for the given context
dstartstop[0] = targetTime[0];
dstartstop[1] = targetTime[0];
din = new TDataType(dstartstop);
dout = new TDataType(data);
String dname = new String("/" + context + "/" + server + "/" + device);
String[] pname = new String[2];
pname[0] = new String(property);
int ntries = 1;
if (!server.endsWith("HISTORY"))
{ // not a call to a central archive server
if (!isArchiveQueryProperty(property))
{ // meta extension not given, try this ...
pname[0] = property + ".HIST";
pname[1] = property + ".ARCH";
ntries = 2;
}
}
for (int i=0; i<ntries; i++)
{
TLink tl = new TLink(dname,pname[i],dout,din,TAccess.CA_READ);
cc = tl.execute(2000, true);
targetTime[0] = tl.getLastDataTimeStamp();
tl.close();
if (cc == 0 && dout.getCompletionLength() > 0) break;
}
return cc;
}
/**
* Retrieves an archive data set.
*
* Retrieve an archive data set (value - timestamp pairs) for the target property and device
* given and over the time range specified. If server is null, an empty string, or "HISTORY",
* the central archive server is queried for the data. Otherwise the local history
* subsystem of the device server specified is queried.
*
* @param context is the desired context
* @param server is the device server which manages the archived parameter. If null
* then the central archive will be queried for the property and device
* @param property is the desired archived property
* @param device is the desired device name
* @param start is the start time in seconds (UTC double, a TINE timestamp)
* @param stop is the stop time in seconds (UTC double, a TINE timestamp)
* @param data is a reference to a (doublet) data array object to contain the returned data.
* This can be one of FLTINT[], DBLDBL[], NAME64I[], and so on. The array should be
* dimensioned to the maximum number of points desired (effectively determining a raster
* over which the archived data will be distributed.
* The reference object can also be an array of HISTORY[] object instances, which have been
* constructed with the desired data type (usually a compound data type) to be returned.
* The number of points returned in the call will often be less than array dimension
* so one should pay attention to the return value of the call.
*
* @return if positive, the number of points returned in the archive call; if negative,
* the negative of a TINE error code.
*/
public static int getArchivedData(String context,String server, String property, String device, double start, double stop,TCompoundDataObject[] data)
{
return getArchivedDataArray(context,server,property,device,0,start,stop,data);
}
public static int getArchivedData(String context,String server, String property, String device, double start, double stop,DBLDBL[] data)
{
return getArchivedDataArray(context,server,property,device,0,start,stop,data);
}
/**
* Retrieves an archive data set.
*
* Retrieve an archive data set (value - timestamp pairs) for the target property and device
* given and over the time range specified. Both the central archive and local archive are
* queried for the number of stored points over the interval. Data are usually
* retrieved from the central archive system if there are at least 500 points over the
* time interval in question. Otherwise the local archive system is used. By examining
* the THistorySource object one can see which source was chosen and how many points both
* sources have over the interval. For dedicated retrieval from one source or the
* other, please use an overloaded method which does not take the THistorySource parameter!
*
* @param context is the desired context
* @param server is the device server which manages the archived parameter. If null
* then the central archive will be queried for the property and device
* @param property is the desired archived property
* @param device is the desired device name
* @param start is the start time in seconds (UTC double, a TINE timestamp)
* @param stop is the stop time in seconds (UTC double, a TINE timestamp)
* @param data is a reference to a (doublet) data array object to contain the returned data.
* This can be one of FLTINT[], DBLDBL[], NAME64I[], and so on. The array should be
* dimensioned to the maximum number of points desired (effectively determining a raster
* over which the archived data will be distributed.
* The reference object can also be an array of HISTORY[] object instances, which have been
* constructed with the desired data type (usually a compound data type) to be returned.
* The src parameter will give the
* exact number of points actually stored over the interval specified.
* The number of points returned in the call will often be less than array dimension and
* less than the exact number of points stored over the interval.
* @param src is a reference to a THistorySource object to receive the history source information.
* @param timeout gives the number of milliseconds to wait for the call to complete
* (usually 1000 is sufficient).
* @return 0 upon success or a TINE error code.
*/
public static int getArchivedData(String context,String server, String property, String device, double start, double stop,TCompoundDataObject[] data,THistorySource src,int timeout)
{
return getDataArray(context,server,property,device,0,start,stop,data,src,timeout);
}
public static int getArchivedData(String context,String server, String property, String device, double start, double stop,DBLDBL[] data,THistorySource src,int timeout)
{
return getDataArray(context,server,property,device,0,start,stop,data,src,timeout);
}
public static int getArchivedData(String context,String server, String property, String device, double start, double stop,TCompoundDataObject[] data,THistorySource src,int timeout,boolean extendedRange)
{
return getArchivedData(context,server,property,device,0,start,stop,data,src,timeout,extendedRange);
}
public static int getArchivedData(String context,String server, String property, String device, double start, double stop,DBLDBL[] data,THistorySource src,int timeout,boolean extendedRange)
{
return getArchivedData(context,server,property,device,0,start,stop,data,src,timeout,extendedRange);
}
public static int getArchivedData(String context,String server, String property, String device, int index, double start, double stop,TCompoundDataObject[] data,THistorySource src,int timeout,boolean extendedRange)
{
if (extendedRange)
{
start -= HEARTBEAT*2;
stop += HEARTBEAT*2;
if (src != null) src.setExtendedTimeRange(true);
}
return getDataArray(context,server,property,device,index,start,stop,(TCompoundDataObject[])data,src,timeout);
}
/**
* Retrieves an archive data set.
*
* Retrieve an archive data set (value - timestamp pairs) for the target property and device
* given and over the time range specified. If server is null, an empty string, or "HISTORY",
* the central archive server is queried for the data. Otherwise the local history
* subsystem of the device server specified is queried.
*
* @param context is the desired context
* @param server is the device server which manages the archived parameter. If null
* then the central archive will be queried for the property and device
* @param property is the desired archived property
* @param device is the desired device name
* @param start is the start time in seconds (UTC double, a TINE timestamp)
* @param stop is the stop time in seconds (UTC double, a TINE timestamp)
* @param data is a reference to a (doublet) data array object to contain the returned data.
* This can be one of FLTINT[], DBLDBL[], NAME64I[], and so on. The array should be
* dimensioned to the maximum number of points desired (effectively determining a raster
* over which the archived data will be distributed.
* The reference object can also be an array of HISTORY[] object instances, which have been
* constructed with the desired data type (usually a compound data type) to be returned.
* The number of points returned in the call will often be less than array dimension
* so one should pay attention to the return value of the call.
*
* @return if positive, the number of points returned in the archive call; if negative,
* the negative of a TINE error code.
*/
public static int getArchivedData(String context,String server, String property, String device, int index,double start, double stop,TCompoundDataObject[] data)
{
return getArchivedDataArray(context,server,property,device,index,start,stop,data);
}
/**
* Retrieves an archive data set.
*
* Retrieve an archive data set (value - timestamp pairs) for the target property and device
* given and over the time range specified. If server is null, an empty string, or "HISTORY",
* the central archive server is queried for the data. Otherwise the local history
* subsystem of the device server specified is queried.
*
* @param context is the desired context
* @param server is the device server which manages the archived parameter. If null
* then the central archive will be queried for the property and device
* @param property is the desired archived property
* @param device is the desired device name
* @param start is the start time in seconds (UTC double, a TINE timestamp)
* @param stop is the stop time in seconds (UTC double, a TINE timestamp)
* @param data is a reference to a (doublet) data array object to contain the returned data.
* This can be one of FLTINT[], DBLDBL[], NAME64I[], and so on. The array should be
* dimensioned to the maximum number of points desired (effectively determining a raster
* over which the archived data will be distributed.
* The reference object can also be an array of HISTORY[] object instances, which have been
* constructed with the desired data type (usually a compound data type) to be returned.
* The number of points returned in the call will often be less than array dimension
* so one should pay attention to the return value of the call.
* @param timeout gives the number of milliseconds to wait for the call to complete
* (usually 1000 is sufficient).
*
* @return if positive, the number of points returned in the archive call; if negative,
* the negative of a TINE error code.
*/
public static int getArchivedData(String context,String server, String property, String device, int index,double start, double stop,TCompoundDataObject[] data,int timeout)
{
return getArchivedDataArray(context,server,property,device,index,start,stop,data,timeout);
}
/**
* Retrieves an archive data set.
*
* Retrieve an archive data set (value - timestamp pairs) for the target property and device
* given and over the time range specified. If server is null, an empty string, or "HISTORY",
* the central archive server is queried for the data. Otherwise the local history
* subsystem of the device server specified is queried.
*
* @param context is the desired context
* @param server is the device server which manages the archived parameter. If null
* then the central archive will be queried for the property and device
* @param property is the desired archived property
* @param device is the desired device name
* @param start is the start time in seconds (UTC double, a TINE timestamp)
* @param stop is the stop time in seconds (UTC double, a TINE timestamp)
* @param sample is the desired raster sample. Passing a '0' will instruct
* the targeted server to select a raster which will best fill in the
* desired time range. If (e.g.) a '1' is passed then no raster will be
* used. This means that the desired 'stop' time may not have been reached.
* Thus the returned data need to be examined in order to determine whether the
* call should be repeated (after adjusting the 'start' time).
* @param data is a reference to a HISTORY[] data array object to contain the returned data.
* This object passed should be an array of HISTORY instances, which have been
* constructed with the desired data type (usually a compound data type) to be
* returned. The array should be
* dimensioned to the maximum number of points desired (effectively determining a raster
* over which the archived data will be distributed.
* The number of points returned in the call will often be less than array dimension
* so one should pay attention to the return value of the call.
* @param timeout gives the number of milliseconds to wait for the call to complete
* (usually 1000 is sufficient).
*
* @return if positive, the number of points returned in the archive call; if negative,
* the negative of a TINE error code.
*/
public static int getArchivedData(String context,String server, String property, String device, int index,int sample,double start, double stop,TCompoundDataObject[] data,int timeout)
{
return getArchivedDataArray(context,server,property,device,index,sample,start,stop,data,timeout);
}
public static int writeArchivedDataToFile(String filename,String context,String server, String property, String device,double start, double stop)
{
try
{
TPropertyQuery[] tpq = TQuery.getPropertyInformation(context, server, device, property);
if (tpq == null) return TErrorList.non_existent_property;
// THistory.getNumPointsInInterval(context, server, property, device, start, stop, 2000);
// n.b. determine num points in interval with another call and warm user acquisition time if too many
FileWriter fw = new FileWriter(filename);
fw.write("#/"+context+"/"+server+"/"+device+"["+property+"], ("+tpq[0].prpUnits+"), start "+TDataTime.toString(start)+", stop "+TDataTime.toString(stop)+"\r\n");
fw.write("time string, time stamp, system stamp, value\r\n");
double ts=0, srtt = start;
int ntot = 0, npts = 1000;
HISTORY[] hsts = new HISTORY[1000];
for (int i=0; i<1000; i++)
{
hsts[i] = new HISTORY(new TDataType(1,tpq[0].prpFormat));
}
TDataType tdt;
String lnout;
long t = System.currentTimeMillis();
while (npts == 1000)
{
npts = THistory.getArchivedData(context, server, property,device, 0, 1,srtt, stop, hsts, 1000);
for (int k=0; k<npts; k++)
{
tdt = hsts[k].getDataObject();
ts = (double)tdt.getDataTimeStamp()/1000.0;
lnout = TDataTime.toString(ts)+", "+String.format("%10.3f", ts)+", "+tdt.getSystemDataStamp()+", "+tdt.toString()+"\n";
fw.write(lnout);
}
ntot += npts;
if (ts <= srtt) break;
srtt = ts;
}
t = System.currentTimeMillis() - t;
fw.write("#access time:, "+t+" (msec), number points in interval:, "+ntot+"\n");
fw.close();
}
catch (Exception x)
{
System.out.println("cannot write to "+filename+" : "+x.getMessage());
return TErrorList.code_failure;
}
return 0;
}
/**
* Retrieves the total number of stored data points in the interval specified.
*
* Retrieve the number of points stored for the given parameters
* and over the time range specified. If server is null, an empty string, or "HISTORY",
* the central archive server is queried for the data. Otherwise the local history
* subsystem of the device server specified is queried.
*
* @param context is the desired context
* @param server is the device server which manages the archived parameter. If null
* then the central archive will be queried for the property and device
* @param property is the desired archived property
* @param device is the desired device name
* @param start is the start time in seconds (UTC double, a TINE timestamp)
* @param stop is the stop time in seconds (UTC double, a TINE timestamp)
*
* @return if positive, the number of points returned in the archive call; if negative,
* the negative of a TINE error code.
*/
public static int getNumPointsInInterval(String context,String server, String property, String device, double start, double stop)
{
return getArchivedNumPointsInInterval(context, server, property, device, start, stop, 1000);
}
/**
* Retrieves the total number of stored data points in the interval specified.
*
* Retrieve the number of points stored for the given parameters
* and over the time range specified. If server is null, an empty string, or "HISTORY",
* the central archive server is queried for the data. Otherwise the local history
* subsystem of the device server specified is queried.
*
* @param context is the desired context
* @param server is the device server which manages the archived parameter. If null
* then the central archive will be queried for the property and device
* @param property is the desired archived property
* @param device is the desired device name
* @param start is the start time in seconds (UTC double, a TINE timestamp)
* @param stop is the stop time in seconds (UTC double, a TINE timestamp)
* @param timeout gives the number of milliseconds to wait for the call to complete
* (usually 1000 is sufficient).
*
* @return if positive, the number of points returned in the archive call; if negative,
* the negative of a TINE error code.
*/
public static int getNumPointsInInterval(String context,String server, String property, String device, double start, double stop,int timeout)
{
return getArchivedNumPointsInInterval(context, server, property, device, start, stop, timeout);
}
/**
* Retrieves an archived data array 'snapshot' at the time specified.
*
* Retrieve an archive data set for the target property and device
* given at the time specified. If server is null, an empty string, or "HISTORY",
* the central archive server is queried for the data. Otherwise the local history
* subsystem of the device server specified is queried. The returned data set
* represents the entire data array, be it a multi-channel array, trace array, or
* scalar at a stored time nearest (but not greater than) the given time.
*
* @param context is the desired context
* @param server is the device server which manages the archived parameter. If null
* then the central archive will be queried for the property and device
* @param property is the desired archived property
* @param device is the desired device name
* @param targetTime is the targetted time in seconds (UTC double, a TINE timestamp)
* This is passed as a single-valued array, so that the targetted time can be
* altered by the call to reflect the time found.
* @param data is a reference to a String data array object to contain the returned data.
* The array should be dimensioned to the number of points in the data record.
*
* @return 0 if success or a TINE error code.
*/
public static int getArchivedSnapshot(String context,String server, String property, String device, double[] targetTime,String[] data)
{
return getArchivedDataSnapshot(context,server,property,device,targetTime,data);
}
/**
* Retrieves an archived data array 'snapshot' at the time specified.
*
* Retrieve an archive data set for the target property and device
* given at the time specified. If server is null, an empty string, or "HISTORY",
* the central archive server is queried for the data. Otherwise the local history
* subsystem of the device server specified is queried. The returned data set
* represents the entire data array, be it a multi-channel array, trace array, or
* scalar at a stored time nearest (but not greater than) the given time.
*
* @param context is the desired context
* @param server is the device server which manages the archived parameter. If null
* then the central archive will be queried for the property and device
* @param property is the desired archived property
* @param device is the desired device name
* @param targetTime is the targetted time in seconds (UTC double, a TINE timestamp)
* This is passed as a single-valued array, so that the targetted time can be
* altered by the call to reflect the time found.
* @param data is a reference to a float data array object to contain the returned data.
* The array should be dimensioned to the number of points in the data record.
*
* @return 0 if success or a TINE error code.
*/
public static int getArchivedSnapshot(String context,String server, String property, String device, double[] targetTime,float[] data)
{
return getArchivedDataSnapshot(context,server,property,device,targetTime,data);
}
public static int addToLocalHistory(
String context,String server, String property, String device,
int datasiz,int datafmt,int pollInterval,int archInterval,
int depthShort,int depthLong,int heartBeat,float pTolerance,float aTolerance)
{
THistoryRecordStruct[] hrs = new THistoryRecordStruct[1];
THistorySpecification hsp = new THistorySpecification(pollInterval, archInterval, depthShort, depthLong, heartBeat, pTolerance, aTolerance, null);
hrs[0] = new THistoryRecordStruct(device, property, datasiz, datafmt, hsp);
String dev = "/"+context+"/"+server;
TLink lnk = new TLink(dev,"ADDHISTORY",null,new TDataType(hrs),TAccess.CA_WRITE);
return lnk.executeAndClose();
}
public static String[] getLocalHistoryProperties(String context,String server,String device)
{
int[] n = new int[1];
String dev = "/"+context+"/"+server;
TLink lnk = new TLink(dev,"NHISTORIES",new TDataType(n),null,TAccess.CA_READ);
if (lnk.executeAndClose() != 0) return null;
if (n[0] == 0)
{ // could be a doocs server
String eqm = TSrvEntry.getSrvEntryEqmName(context, server);
if (eqm == null || eqm.compareTo(TSrvEntry.DOOCSEQM) != 0) return null;
String[] prps = TQuery.getDeviceProperties(context, server, device);
if (prps == null) return null;
ArrayList<String>al = new ArrayList<String>();
for (String p : prps)
{
if (p.endsWith(".HIST")) al.add(p.substring(0, p.lastIndexOf('.')));
}
if (al.isEmpty()) return null;
return al.toArray(new String[0]);
}
NAME64[] nlst = new NAME64[n[0]];
lnk = new TLink(dev,"HISTORIES",new TDataType(nlst),null,TAccess.CA_READ);
if (lnk.executeAndClose() != 0) return null;
return NameToString.nameArrayToString(nlst);
}
public static THistoryRecordStruct getLocalHistoryRecord(
String context,String server, String property, String device)
{
THistoryRecordStruct[] hrs = new THistoryRecordStruct[1];
hrs[0] = new THistoryRecordStruct();
String dev = "/"+context+"/"+server;
TDataType dout = new TDataType(hrs);
TDataType din = new TDataType(property.toCharArray());
TLink lnk = new TLink(dev,"HISTORIES",dout,din,TAccess.CA_READ);
int cc = lnk.executeAndClose();
if (cc != 0) return null;
if (dout.getCompletionLength() < 1) return null;
return hrs[0];
}
/**
* Retrieve a list of properties archived by the central archive server for the context given.
*
* @param context is the targeted context
*
* @return a list of available archived properties
*/
public static String[] getArchivedProperties(String context)
{
return getArchivedProperties(context,null,null);
}
/**
* Retrieve a list of properties archived by the given server.
*
* @param context is the targeted server context
* @param server is the targeted server name
*
* @return a list of available archived properties
*/
public static String[] getArchivedProperties(String context,String server)
{
return getArchivedProperties(context,server,null);
}
/**
* Retrieve a list of properties archived by the given server.
*
* @param context is the targeted server context
* @param server is the targeted server name
* @param subsystem is the targeted subsystem
* (applicable when the server = "HISTORY", i.e. the central archive server)
*
* @return a list of available archived properties
*/
public static String[] getArchivedProperties(String context,String server,String subsystem)
{
if (server == null && context == null) return null;
if (context == null) context = "DEFAULT";
if (server == null) server = "HISTORY";
boolean isCentral = isCentralArchiveServer(server);
TDataType dtsubs;
if (subsystem != null && subsystem.length() > 0 &&
!subsystem.startsWith("ALL") && !subsystem.startsWith("All"))
{
dtsubs = new TDataType(subsystem);
}
else
{
dtsubs = new TDataType();
}
NAME32[] nlist = null; //TODO: why not NAME64 ?
int[] nprps = new int[1];
String ntagsString, tagsString;
TDataType dtnprps = new TDataType(nprps);
TDataType dtprps;
tagsString = isCentral ? "TAGS" : "HISTORIES";
ntagsString = "N" + tagsString;
String dname = "/" + context + "/" + server;
TLink tl = new TLink(dname,ntagsString,dtnprps,dtsubs,TAccess.CA_READ);
int cc = tl.execute(800, true);
tl.close();
if (cc != 0)
{ // TODO: throw an exception here
return null;
}
if (nprps[0] > 0)
{
nlist = new NAME32[nprps[0]];
dtprps = new TDataType(nlist);
tl = new TLink(dname,tagsString,dtprps,dtsubs,TAccess.CA_READ);
cc = tl.execute(800, true);
tl.close();
if (cc != 0)
{ // TODO: throw an exception here
return null;
}
}
if (nlist == null) return null;
String nam;
Vector<String> v = new Vector<String>(nlist.length);
int n = 0;
for (int i=0; i<nlist.length; i++)
{
nam = nlist[i].getName();
if (nam.endsWith(".NAM")) continue;
if (nam.endsWith(".ENUM")) continue;
if (nam.endsWith(".SRCADDR")) continue;
if (nam.endsWith(".DESC")) continue;
v.add(nam);
n++;
}
return v.toArray(new String[n]);
}
public static String[] getAnnotatedProperties(String context,double start, double stop, int timeout)
{
if (context == null) return null;
NAME64[] nlist = null;
double[] ststp = new double[]{start,stop};
String dname = "/"+context+"/HISTORY";
nlist = new NAME64[100];
TLink tl = new TLink(dname,"RECORDS.WITH.CMTS",new TDataType(nlist),new TDataType(ststp),TAccess.CA_READ);
int cc = tl.executeAndClose(800);
if (cc != 0)
{ // TODO: throw an exception here
return null;
}
return NameToString.nameArrayToString(nlist,tl.getOutputDataObject().getCompletionLength());
}
private static void fillinHstPrpVectors(NAME64[] plist,int len,Vector<String> nv,Vector<String> ev,Vector<String> sav, Vector<String> dv)
{
String p, ucnam;
for (int i=0; i<len; i++)
{
ucnam = plist[i].getName().toUpperCase();
if (ucnam.endsWith(".NAM"))
{
p = ucnam.substring(0, ucnam.lastIndexOf(".NAM"));
if (!nv.contains(p)) nv.add(p); continue;
}
if (ucnam.endsWith(".ENUM"))
{
p = ucnam.substring(0, ucnam.lastIndexOf(".ENUM"));
if (!ev.contains(p)) ev.add(p); continue;
}
if (ucnam.endsWith(".SRCADDR"))
{
p = ucnam.substring(0, ucnam.lastIndexOf(".SRCADDR"));
if (!sav.contains(p)) sav.add(p); continue;
}
if (ucnam.endsWith(".DESC"))
{
int idx = ucnam.lastIndexOf(".NAM.DESC");
if (idx < 0) idx = ucnam.lastIndexOf(".DESC");
p = ucnam.substring(0, idx);
if (!dv.contains(p)) dv.add(p); continue;
}
}
}
/**
* Retrieve a list of properties archived by the given server as a list of
* HstPrp instances, where additional information is returned along with the
* property name.
*
* @param context is the targeted server context
* @param server is the targeted server name
* @param subsystem is the targeted subsystem
* (applicable when the server = "HISTORY", i.e. the central archive server)
*
* @return a list of available archived properties
*/
public static HstPrp[] getArchivedPropertyList(String context,String server,String subsystem)
{
if (server == null && context == null) return null;
if (context == null) context = "DEFAULT";
if (server == null) server = "HISTORY";
boolean isCentral = isCentralArchiveServer(server);
TDataType dtsubs;
if (subsystem != null && subsystem.length() > 0 &&
!subsystem.startsWith("ALL") && !subsystem.startsWith("All"))
{
dtsubs = new TDataType(subsystem);
}
else
{
dtsubs = new TDataType();
}
NAME64[] nlist = null;
int[] nprps = new int[1];
String ntagsString, tagsString;
tagsString = isCentral ? "TAGS" : "HISTORIES";
ntagsString = "N" + tagsString;
String dname = "/" + context + "/" + server;
TLink tl = new TLink(dname,ntagsString,new TDataType(nprps),dtsubs,TAccess.CA_READ);
int cc = tl.executeAndClose(800);
if (cc != 0)
{ // TODO: throw an exception here
return null;
}
if (nprps[0] > 0)
{ // get OFFICIAL list of archived elements
nlist = new NAME64[nprps[0]];
tl = new TLink(dname,tagsString, new TDataType(nlist),dtsubs,TAccess.CA_READ);
cc = tl.executeAndClose(800);
if (cc != 0)
{ // TODO: throw an exception here
return null;
}
}
if (nlist == null) return null;
String ucnam, nam;
Vector<String> nv = new Vector<String>(nlist.length);
Vector<String> ev = new Vector<String>(25);
Vector<String> sav = new Vector<String>(nlist.length);
Vector<String> dv = new Vector<String>(25);
Hashtable<String,HstPrp> pl = new Hashtable<String,HstPrp>();
for (int i=0; i<nlist.length; i++)
{
nam = nlist[i].getName();
if (nam.trim().length() == 0) continue;
ucnam = nam.toUpperCase();
if (ucnam.endsWith(".NAM"))
{
nv.add(ucnam.substring(0, ucnam.indexOf(".NAM"))); continue;
}
if (ucnam.endsWith(".ENUM"))
{
ev.add(ucnam.substring(0, ucnam.indexOf(".ENUM"))); continue;
}
if (ucnam.endsWith(".SRCADDR"))
{
sav.add(ucnam.substring(0, ucnam.indexOf(".SRCADDR"))); continue;
}
if (ucnam.endsWith(".DESC"))
{
int idx = ucnam.indexOf(".NAM.DESC");
if (idx < 0) idx = ucnam.indexOf(".DESC");
dv.add(ucnam.substring(0, idx)); continue;
}
pl.put(ucnam, new HstPrp(nam));
}
if (pl.isEmpty()) return new HstPrp[0];
if (isCentral)
{ // take care of other contingencies at the Central Archive Server
NAME64[] plist = new NAME64[nlist.length*2];
TDataType tdt = new TDataType(plist);
tl = new TLink(dname,"PROPERTIES",tdt,null,TAccess.CA_READ);
if (tl.executeAndClose(800) == 0)
{
fillinHstPrpVectors(plist,tdt.getCompletionLength(),nv,ev,sav,dv);
}
tl = new TLink(dname,"SRVALIASLIST",tdt,null,TAccess.CA_READ);
if (tl.executeAndClose(800) == 0)
{
fillinHstPrpVectors(plist,tdt.getCompletionLength(),nv,ev,sav,dv);
}
}
HstPrp hp;
for (String s : nv) if ((hp=pl.get(s)) != null) hp.hasNameList = true;
for (String s : ev) if ((hp=pl.get(s)) != null) hp.hasEnumList = true;
for (String s : sav) if ((hp=pl.get(s)) != null) hp.hasSrcList = true;
for (String s : dv) if ((hp=pl.get(s)) != null) hp.hasDescList = true;
return pl.values().toArray(new HstPrp[pl.size()]);
}
private static String selectedContext = null;
private static Hashtable<String, String> srcTbl = null;
public static String getHistoryServerDropString(String context,String sourceDropString)
{
if (sourceDropString == null) return sourceDropString;
if (sourceDropString.startsWith("TINE/")) return sourceDropString;
if (selectedContext == null || selectedContext.compareToIgnoreCase(context) != 0)
{
selectedContext = context;
srcTbl = getArchivedSources(context,"HISTORY",1000);
if (srcTbl == null)
return sourceDropString.startsWith("/") ? "TINE"+sourceDropString : "TINE/"+sourceDropString;
}
String key;
int idx = sourceDropString.indexOf('[');
if (idx > 0)
{
key = sourceDropString;
}
else
{
idx = sourceDropString.lastIndexOf('/');
if (idx < 0) // punt
return sourceDropString.startsWith("/") ? "TINE"+sourceDropString : "TINE/"+sourceDropString;
String prp = sourceDropString.substring(idx+1);
key = sourceDropString.substring(0,idx)+"["+prp+"]";
}
if (srcTbl == null) // punt
return sourceDropString.startsWith("/") ? "TINE"+sourceDropString : "TINE/"+sourceDropString;
if (!key.startsWith("/")) key = "/"+key;
if (srcTbl.containsKey(key))
{
String v = srcTbl.get(key);
key = "/"+context+"/ARCHIVER/"+v;
}
// re-form to the viewers expectation
idx = key.indexOf('[');
if (idx < 0) return "TINE"+key; // punt
int lidx = key.indexOf(']');
String prp = key.substring(idx+1,lidx);
key = key.substring(0,idx)+"/"+prp;
return "TINE"+key;
}
public static Hashtable<String, String> getArchivedSources(String context,String server,int timeout)
{
Hashtable<String, String> srcTbl = new Hashtable<String, String>();
if (server == null && context == null) return null;
if (context == null) context = "DEFAULT";
if (server == null) server = "HISTORY";
NAME64[] nlist = new NAME64[1000];
TDataType dtprps = new TDataType(nlist);
String dname = "/" + context + "/" + server;
TLink tl = new TLink(dname,"*.SRCADDR",dtprps,null,TAccess.CA_READ);
int cc = tl.executeAndClose(800);
if (cc != 0)
{ // TODO: throw an exception here
return null;
}
int listsize = dtprps.getCompletionLength();
if (listsize > 0)
{
String prp;
String[] srcs;
for (int i=0; i<listsize; i++)
{
prp = nlist[i].getName();
prp = prp.substring(0, prp.length()-8);
srcs = getArchiveSource(context, server, prp, "#0", timeout);
if (srcs != null)
{
String key = "keyword["+prp+"]";
String dev;
String[] devs = null;
if (srcs.length > 1)
{
devs = TQuery.getDeviceNames(context, server, prp);
}
for (int k=0; k<srcs.length; k++)
{ // key is the src string (per device)
if (srcs[k] == null) break;
if (srcs.length > 1)
{
dev = (devs == null || k >= devs.length) ? "#"+k : devs[k];
key = dev+"["+prp+"]";
}
srcTbl.put(srcs[k],key);
}
}
}
return srcTbl;
}
return null;
}
/**
* Retrieve a list of archived devices for the given server and property.
*
* @param context is the targeted server context
* @param server is the targeted server name
* @param property is the targeted property
*
* @return a list of available archived device names
*/
public static String[] getArchivedDevices(String context,String server, String property)
{
return TQuery.getDeviceNames(context, server, property);
}
/**
* Retrieve a list of available subsystems at the central archive server for the given context
*
* @param context is the targeted server context
*
* @return a list of available subsystems
*/
public static String[] getArchivedSubsystems(String context)
{
return getArchivedSubsystems(context,null);
}
public static String[] getArchivedSubsystems(String context,String server)
{
if (server == null && context == null) return null;
if (context == null) context = "DEFAULT";
if (server == null) server = "HISTORY"; // assume the standard central archive server for the given context
if (!isCentralArchiveServer(server)) return null;
int cc;
NAME32[] nlist = null;
int[] nsubs = new int[1];
String ntagsString, tagsString;
TDataType dtnsubs = new TDataType(nsubs);
TDataType dtsubs;
tagsString = "SUBSYSTEMS";
ntagsString = "N" + tagsString;
String dname = "/" + context + "/" + server;
TLink tl = new TLink(dname,ntagsString,dtnsubs,null,TAccess.CA_READ);
cc = tl.execute(800, true);
tl.close();
if (cc != 0)
{ // TODO: throw an exception here
return null;
}
if (nsubs[0] > 0)
{
nlist = new NAME32[nsubs[0]];
dtsubs = new TDataType(nlist);
tl = new TLink(dname,tagsString,dtsubs,null,TAccess.CA_READ);
cc = tl.execute(800, true);
tl.close();
if (cc != 0)
{ // TODO: throw an exception here
return null;
}
}
String nam;
Vector<String> v = new Vector<String>(nlist.length);
int n = 0;
for (int i=0; i<nlist.length; i++)
{
nam = nlist[i].getName();
if (nam.length() == 0) continue;
v.add(nam);
n++;
}
return v.toArray(new String[n]);
}
public static String[] getOperationHistoryContexts()
{
return TQuery.getContexts("STATE");
}
public static String[] getOperationHistoryContexts(String importance)
{
return TQuery.getContexts("STATE",importance);
}
/**
* Retrieve a list of available contexts where a central archive server exists
*
* @return a list of available contexts
*/
public static String[] getArchiveServerContexts()
{
return TQuery.getContexts("HISTORY");
}
/**
* Retrieve a list of available contexts where a central archive server exists
* and has the importance specified
*
* @param importance is the targeted importance level
* (one of "ALL", "IMPORTANT", "CRITICAL", "ESSENTIAL")
* @return a list of available contexts
*/
public static String[] getArchiveServerContexts(String importance)
{
return TQuery.getContexts("HISTORY",importance);
}
public static String[] getOperationHistoryConfigurationNames(String context)
{
if (context == null) return null;
return TQuery.getDeviceNames(context, "STATE", "CONFIGURATION");
}
public static String[] getViewerMcaConfigurationNames(String context)
{
if (context == null) return null;
return TQuery.getDeviceNames(context, "HISTORY", "CONFIGURATION.MCA");
}
public static String[] getViewerConfigurationNames(String context)
{
if (context == null) return null;
return TQuery.getDeviceNames(context, "HISTORY", "CONFIGURATION");
}
public static String[] getViewerTraceConfigurationNames(String context)
{
if (context == null) return null;
String[] nms = TQuery.getDeviceNames(context, "HISTORY", "CONFIGURATION.TRACE");
if (nms == null || nms.length < 2) return nms;
String[] nmsr = new String[nms.length-2];
boolean hasProperties = false, hasTraces = false;
for (int i=0, k=0; i<nms.length; i++)
{
if (nms[i].compareToIgnoreCase("properties") == 0)
{
hasProperties = true;
continue;
}
if (nms[i].compareToIgnoreCase("traces") == 0)
{
hasTraces = true;
continue;
}
if (k<nms.length-2) nmsr[k++] = nms[i];
}
return hasProperties && hasTraces ? nmsr : nms;
}
public static String[] getViewerConfigurationNames(String context,String group)
{
if (context == null) return null;
String prp = "CONFIGURATION";
if (group != null) prp += "." + group;
String[] nms = TQuery.getDeviceNames(context, "HISTORY", prp);
if (nms == null || nms.length < 2) return nms;
String[] nmsr = new String[nms.length-1];
boolean hasProperties = false;
for (int i=0, k=0; i<nms.length; i++)
{
if (nms[i].compareToIgnoreCase("properties") == 0)
{
hasProperties = true;
continue;
}
if (k<nms.length-1) nmsr[k++] = nms[i];
}
return hasProperties ? nmsr : nms;
}
public static HstView[] getViewerConfigurationList(String context,String group)
{
if (context == null) return null;
if (!isInitialized) initCfgs();
String prp = "CONFIGURATION";
if (group != null) prp += "." + group;
prp += ".NAM";
TDataType dout = new TDataType(views);
String dname = "/" + context + "/HISTORY";
TLink tl = new TLink(dname,prp,dout,null,TAccess.CA_READ);
if (tl.executeAndClose(1000) != 0) return null;
int len = dout.getCompletionLength();
if (len == 0) return null;
HstView[] list = new HstView[len];
for (int i=0; i<len; i++) list[i] = new HstView(views[i]);
return list;
}
public static int setViewerConfigurationList(String context,String group,HstView[] list)
{
if (context == null || list == null) return TErrorList.argument_list_error;
if (!isInitialized) initCfgs();
String prp = "CONFIGURATION";
if (group != null) prp += "." + group;
prp += ".NAM";
TDataType din = new TDataType(list);
String dname = "/" + context + "/HISTORY";
TLink tl = new TLink(dname,prp,null,din,TAccess.CA_WRITE);
return tl.executeAndClose(800);
}
public static String[] getViewerConfigurationGroups(String context)
{
if (context == null) return null;
NAME64[] prps = new NAME64[100];
TDataType dtprps = new TDataType(prps);
String dname = "/" + context + "/HISTORY";
String dprop = "CONFIGURATION.*";
TLink tl = new TLink(dname,dprop,dtprps,null,TAccess.CA_READ);
int cc = tl.execute(800, true);
tl.close();
if (cc != 0)
{ // TODO: throw an exception here
return null;
}
int len = dtprps.getCompletionLength();
String nam;
Vector<String> v = new Vector<String>(len);
int n = 0;
for (int i=0; i<len; i++)
{
nam = prps[i].getName();
if (nam.compareToIgnoreCase("CONFIGURATION") == 0) continue;
if (nam.length() == 0) continue;
if (nam.endsWith(".NAM")) continue;
if (nam.endsWith(".MCA")) continue;
if (nam.endsWith(".TRACE")) continue;
v.add(nam.substring(14));
n++;
}
return n > 0 ? v.toArray(new String[n]) : null;
}
public static HstCfg[] getSelectableProptiesConfiguration(String context,String group)
{
if (context == null || group == null) return null;
return getViewerConfiguration(context,"properties",group);
}
public static HstCfg[] getSelectableTracesConfiguration(String context)
{
if (context == null) return null;
return getViewerConfiguration(context,"traces","TRACE");
}
public static HstCfg[] getViewerConfiguration(String context,String name)
{
return getViewerConfiguration(context,name,null);
}
public static synchronized HstCfg[] getViewerConfiguration(String context,String name,String group)
{
if (context == null || name == null) return null;
if (!isInitialized) initCfgs();
TDataType dtcfg = new TDataType(cfgs);
String dname = "/" + context + "/HISTORY/" + name;
String dprop = "CONFIGURATION";
if (group != null && group.length() > 0) dprop += "." + group;
TLink tl = new TLink(dname,dprop,dtcfg,null,TAccess.CA_READ);
int cc = tl.execute(800, true);
tl.close();
if (cc != 0)
{ // TODO: throw an exception here
DbgLog.log("getViewerConfiguration",TErrorList.getErrorString(cc));
return null;
}
int num = dtcfg.getCompletionLength();
if (num == 0) return null;
boolean hasPropertiesList = false;
for (int i=0; i<num; i++)
{ // is 'properties' in the list ?
if (cfgs[i].getDescription().compareToIgnoreCase("properties") == 0)
{
hasPropertiesList = true;
break;
}
}
int ncfg = hasPropertiesList ? num - 1 : num;
HstCfg[] cfg = new HstCfg[ncfg];
for (int i=0, n=0; i<num; i++)
{
if (cfgs[i].getDescription().compareToIgnoreCase("properties") != 0)
{
cfg[n++] = new HstCfg(cfgs[i]);
}
}
return cfg;
}
public static synchronized int setViewerConfiguration(String context,String name,String group,HstCfg[] hstCfgs)
{
if (context == null || name == null) return TErrorList.argument_list_error;
if (!isInitialized) initCfgs();
TDataType dtcfg = new TDataType(hstCfgs);
String dname = "/" + context + "/HISTORY/" + name;
String dprop = "CONFIGURATION";
if (group != null && group.length() > 0) dprop += "." + group;
TLink tl = new TLink(dname,dprop,null,dtcfg,TAccess.CA_WRITE);
return tl.executeAndClose(800);
}
public static synchronized int setTraceViewerConfiguration(String context,String name,HstCfg[] hstCfgs)
{
if (context == null || name == null) return TErrorList.argument_list_error;
if (!isInitialized) initCfgs();
TDataType dtcfg = new TDataType(hstCfgs);
String dname = "/" + context + "/HISTORY/" + name;
String dprop = "CONFIGURATION.TRACE";
TLink tl = new TLink(dname,dprop,null,dtcfg,TAccess.CA_WRITE);
return tl.executeAndClose(800);
}
public static synchronized McaCfg[] getMcaViewerConfiguration(String context,String name)
{
if (context == null || name == null) return null;
if (!isInitialized) initCfgs();
TDataType dtcfg = new TDataType(mcacfgs);
String dname = "/" + context + "/HISTORY/" + name;
String dprop = "CONFIGURATION.MCA";
TLink tl = new TLink(dname,dprop,dtcfg,null,TAccess.CA_READ);
int cc = tl.execute(800, true);
tl.close();
if (cc != 0)
{ // TODO: throw an exception here
DbgLog.log("getMcaViewerConfiguration",TErrorList.getErrorString(cc));
return null;
}
int num = dtcfg.getCompletionLength();
if (num == 0) return null;
McaCfg[] cfg = new McaCfg[num];
for (int i=0; i<num; i++)
{
cfg[i] = new McaCfg(mcacfgs[i]);
}
return cfg;
}
public static synchronized int setMcaViewerConfiguration(String context,String name,McaCfg[] mcaCfgs)
{
if (context == null || name == null) return TErrorList.argument_list_error;
if (!isInitialized) initCfgs();
TDataType dtcfg = new TDataType(mcaCfgs);
String dname = "/" + context + "/HISTORY/" + name;
String dprop = "CONFIGURATION.MCA";
TLink tl = new TLink(dname,dprop,null,dtcfg,TAccess.CA_WRITE);
return tl.executeAndClose(800);
}
public static synchronized McaCfg[] getOperationHistoryConfiguration(String context,String name)
{
if (context == null || name == null) return null;
if (!isInitialized) initCfgs();
TDataType dtcfg = new TDataType(mcacfgs);
String dname = "/" + context + "/STATE/" + name;
String dprop = "CONFIGURATION";
TLink tl = new TLink(dname,dprop,dtcfg,null,TAccess.CA_READ);
int cc = tl.execute(800, true);
tl.close();
if (cc != 0)
{ // TODO: throw an exception here
DbgLog.log("getOperationHistoryConfiguration",TErrorList.getErrorString(cc));
return null;
}
int num = dtcfg.getCompletionLength();
if (num == 0) return null;
McaCfg[] cfg = new McaCfg[num];
for (int i=0; i<num; i++)
{
cfg[i] = new McaCfg(mcacfgs[i]);
}
return cfg;
}
public static synchronized PrfCfg[] getOperationHistoryProfile(String context,String name)
{
if (context == null || name == null) return null;
if (!isInitialized) initCfgs();
TDataType dtcfg = new TDataType(prfcfgs);
String dname = "/" + context + "/STATE/" + name;
String dprop = "PROFILE";
TLink tl = new TLink(dname,dprop,dtcfg,null,TAccess.CA_READ);
int cc = tl.execute(800, true);
tl.close();
if (cc != 0)
{ // TODO: throw an exception here
DbgLog.log("getOperationHistoryProfile",TErrorList.getErrorString(cc));
return null;
}
int num = dtcfg.getCompletionLength();
if (num == 0) return null;
PrfCfg[] cfg = new PrfCfg[num];
for (int i=0; i<num; i++)
{
cfg[i] = new PrfCfg(prfcfgs[i]);
}
return cfg;
}
}