Package de.desy.tine.queryUtils

Source Code of de.desy.tine.queryUtils.TQuery

package de.desy.tine.queryUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;

import de.desy.tine.addrUtils.*;
import de.desy.tine.bitfieldUtils.*;
import de.desy.tine.client.TLink;
import de.desy.tine.client.TLinkFactory;
import de.desy.tine.client.TLinkFactory.AccessLockType;
import de.desy.tine.csvUtils.RowHandler;
import de.desy.tine.csvUtils.csv;
import de.desy.tine.csvUtils.csvColumn;
import de.desy.tine.csvUtils.csvHandler;
import de.desy.tine.dataUtils.TDataType;
import de.desy.tine.definitions.*;
import de.desy.tine.server.TServerSettings;
import de.desy.tine.server.connections.*;
import de.desy.tine.server.equipment.TWriteAccessInfo;
import de.desy.tine.server.logger.*;
import de.desy.tine.server.properties.*;
import de.desy.tine.structUtils.*;
import de.desy.tine.types.*;


/**
* TQuery: Utility with many standard query routines
*
* This is a static class which can be used to make system queries without
* the need for instantiating a TQuery object.
*/
/**
* @author duval
*
*/
public final class TQuery
{
  public static final int nicePropertyQuerySize = 10;
  public static final int niceContextsQuerySize = 100;
  private static int maxQueryBufferSize = 256000;
  private static byte[] hByteBlobX = new byte[nicePropertyQuerySize * XPropertyQuery.sizeInBytes];
  private static byte[] hByteBlobL = new byte[nicePropertyQuerySize * PropertyQueryLegacy.sizeInBytes];
  private static byte[] hByteBlob = new byte[nicePropertyQuerySize * TPropertyQuery.sizeInBytes];
  private static  byte[] hLegacyByteBlob;
  private static String lastQueriedContext = null;
  private static String lastQueriedServer = null;
  private static String lastQueriedDevice = null;
  private static TSrvEntry srvAddr = null;
  public static boolean properties_have_query_function = false;
  public static boolean devices_have_query_function = false;
  /**
   * @param property is the targeted property
   * @return true if the input property represents a stock property of the server
   */
  public static boolean isStockProperty(String property)
  {
    return TStockProperties.isStockProperty(property);
  }
  public static boolean isMetaProperty(String property)
  {
    return TMetaProperties.isMetaProperty(property);
  }
  public static String getModuleAddressInfo()
  { // not thread-safe
    if (srvAddr == null) srvAddr = new TSrvEntry();
    return srvAddr.toString(lastQueriedServer,lastQueriedContext);
  }
  public static String getModuleAddressInfo(String server,String context)
  {
    srvAddr = new TSrvEntry(server,context);
    if (srvAddr.eqmName == null) return "server /"+context+"/"+server+ " unavailable";
    String inf = srvAddr.toString(server,context);
    FECInfo fi = getServerInformation(srvAddr.fecName);
    inf += "\nLocation               : " + fi.getLocation();
    inf += "\nOS                     : " + fi.getOs();
    inf += "\nDescription            : " + fi.getDescription();
    inf += "\nResponsible            : " + fi.getResponsible();
    return inf;
  }
  public static TSrvEntry getModuleAddress(String server,String context)
  {
    return new TSrvEntry(server,context);
  }
  private static String[] getTagList(String context,String tagtype)
  {
    return getTagList(context,tagtype,null);
  }
  private static String[] getTagList(String context,String tagtype,String subsys)
  {
    return getTagList(context,tagtype,subsys,TLink.defaultTimeout);
  }
  private static String[] getTagList(String context,String tagtype,String subsys,int timeout)
  {
    int cc,n,i;
    TDataType dout;
    TDataType din;
    TLink tl;
    StringBuffer host = new StringBuffer(32);
    StringBuffer query = new StringBuffer(32);
    short[] numout = new short[1];
    TDataType numoutData = new TDataType(numout);
    NAME16[] taglist16;
    NAME32[] taglist32;
    String[] strlist;

    if (subsys == null || subsys.compareTo("ALL") == 0)
    {
      din = new TDataType();
    }
    else
    {
      din = new TDataType(subsys);
    }
   
    host.delete(0,31); query.delete(0,31);
    if (context != null && context.length() != 0)
    {
      host.insert(0,"ENS/" + context);
    }
    else
    {
      host.insert(0,"ENS");
    }
    query.insert(0,"N" + tagtype);
    try
    {
      tl = new TLink(host.toString(),query.toString(),numoutData,din,TAccess.CA_READ);
      cc = tl.execute(timeout,true);
      srvAddr = tl.srvAddr;
      tl.close();
    }
    catch (Exception e)
    { // if the host name cannot be resolved -> runtime exception
      MsgLog.log("getTagList", e.getMessage(),TErrorList.non_existent_elem,e,0);
      cc = TErrorList.non_existent_elem;
    }
    if (cc != 0) return null;
    if (numout[0] == 0 && subsys != null && subsys.length() > 0) numout[0] = 100;   
    query.delete(0,31);
    query.insert(0,tagtype);
    n = numout[0];

    taglist32 = new NAME32[n];
    for (i=0; i<n; i++) taglist32[i] = new NAME32();
    if (taglist32.length == 0) return null;
    if (numout[0] > taglist32.length) numout[0] = (short)taglist32.length; 
    dout = new TDataType(taglist32);
    tl = new TLink(host.toString(),query.toString(),dout,din,TAccess.CA_READ);
    cc = tl.execute(TLink.defaultTimeout,true);
    if (dout.getCompletionLength() < n) n = dout.getCompletionLength();
    tl.close();
    if (cc == 0)
    { // this worked, so we're finished
      strlist = new String[n];
      for (i=0; i<n; i++) strlist[i] = taglist32[i].name;     
      return strlist;
    }
    if (cc == TErrorList.illegal_format)
    { // old ENS ? -> try with reduced lengths ...
      taglist16 = new NAME16[n];
      for (i=0; i<n; i++) taglist16[i] = new NAME16();
      if (taglist16.length == 0) return null;
      if (numout[0] > taglist16.length) numout[0] = (short)taglist16.length; 
      dout = new TDataType(taglist16);
      tl = new TLink(host.toString(),query.toString(),dout,din,TAccess.CA_READ);
      cc = tl.execute(TLink.defaultTimeout,true);
      tl.close();
      if (cc != 0) return null;
      strlist = new String[n];
      for (i=0; i<n; i++) strlist[i] = taglist16[i].name;
      return strlist;     
    }
    return null;   
  }
  private static int getNumberOf(String property,String target) throws IOException
  {
    return getNumberOf(property,target,TLink.defaultTimeout);
  }
  private static int getNumberOf(String property,String target,int timeout) throws IOException
  {
    int cc = TErrorList.non_existent_elem;
    short[] n = new short[1];
    TDataType dout;
    TLink tl;
    String propertyq;
   
    if (property == null || target == null) return -TErrorList.argument_list_error;
  
    dout = new TDataType(n);
    propertyq = new String("N" + property);
    try
    {
      tl = new TLink(target,propertyq,dout,null,TAccess.CA_READ);
      cc = tl.execute(timeout,true);
      srvAddr = tl.srvAddr;
      tl.close();
    }
    catch (Exception e)
    {
      cc = TErrorList.host_not_resolved;
    }
    if (cc == TErrorList.link_not_open ||
        cc == TErrorList.connection_timeout ||
        cc == TErrorList.tcp_connect_error)
      throw new IOException("timeout getting information from " + target);
    return cc > 0 ? -cc : (int)n[0];   
  }
  /**
   * Sets the maximum size for use in tine queries.
   *
   * @param size is the size in bytes of the buffer used to hold the query
   * information (65000 bytes is the default)
   * 
   * @return 0 if successful
   */
  public static short setMaximumQueryBufferSize(int size)
  {
    if (size < 4000 || size > 256000) return TErrorList.out_of_range;
    maxQueryBufferSize = size;
    return 0;
  }
  /**
   * Returns a list of Contexts (obtained from the name services)
   *
   * @return A string array containing a list of available contexts as
   * obtained from the Equipment Name Server (ENS) or a null pointer if the call could
   * not complete successfully.  If no contexts were found a
   * string array of zero length is returned.
   */
  public static String[] getContexts()
  {
    if (!TLinkFactory.getInstance().isRunningStandAlone())
    {
      String[] lst = getTagList(null,"CONTEXTS");
      if (lst != null) return lst;
    }
    // then try static cache ...
    return DBQuery.getContextsFromFileCache(null);
  }
  /**
   * Returns a list of Contexts (obtained from the name services)
   * which offer a server with the name specified
   *
   * @param serverName is the targeted server name
   *
   * @return A string array containing a list of available contexts
   * which have the named server or a null pointer if the call could
   * not complete successfully.  If no contexts were found a
   * string array of zero length is returned.
   */
  public static String[] getContexts(String serverName)
  {
    return getContexts(serverName,null);
  }
  /**
   * Returns a list of Contexts (obtained from the name services)
   * which offer a server with the name and importance specified
   *
   * @param serverName is the targeted server name
   * @param imporance is the desired server importance
   * (one of "ALL", "IMPORTANT", "CRITICAL", "ESSENTIAL")
   *
   * @return A string array containing a list of available contexts
   * which have the named server or a null pointer if the call could
   * not complete successfully.  If no contexts were found a
   * string array of zero length is returned.
   */
  public static String[] getContexts(String serverName,String importance)
  {
    if (!TLinkFactory.getInstance().isRunningStandAlone())
    {   
      int cc,n,i;
      TDataType dout;
      TDataType din;
      TLink tl;
      NAME32[] taglist32;
      String[] strlist;
 
      if (serverName == null || serverName.compareToIgnoreCase("ALL") == 0)
      {
        din = new TDataType();
      }
      else if (importance == null)
      {
        din = new TDataType(serverName);
      }
      else
      {
        if (importance.length() == 0) importance = "ALL";
        NAME32[] n32a = new NAME32[2];
        n32a[0] = new NAME32(serverName);
        n32a[1] = new NAME32(importance);
        din = new TDataType(n32a);
      }
      taglist32 = new NAME32[niceContextsQuerySize];
      for (i=0; i<niceContextsQuerySize; i++) taglist32[i] = new NAME32();
      if (taglist32.length == 0) return null;
      dout = new TDataType(taglist32);
      tl = new TLink("/SITE/ENS","CONTEXTS",dout,din,TAccess.CA_READ);
      cc = tl.execute(TLink.defaultTimeout,true);
      tl.close();
      n = dout.getCompletionLength();
      if (cc == 0)
      { // this worked, so we're finished
        strlist = new String[n];
        for (i=0; i<n; i++) strlist[i] = taglist32[i].name;     
        return strlist;
      }
    }
    // try static cache
    return DBQuery.getContextsFromFileCache(serverName);
  }
  public static String[] getDeviceServerReport(String context,String server,String device)
  {
    return getDeviceServerReport(context,server,device,-1);
  }
  public static String[] getDeviceServerReport(String context,String server)
  {
    return getDeviceServerReport(context,server,null,-1);
  }
  public static String[] getDeviceServerReport(String context,String server,String device,int limit)
  {
    ArrayList<String>al = new ArrayList<String>(100);
    String tgt = "/"+context+"/"+server;
    String tgtdev = device; //"#0";
    TSrvEntry se = new TSrvEntry(server,context);
    al.add("server /"+context+"/"+server);
    FECInfo inf = se.getFecAddr().info;
    if (inf == null) inf = TQuery.getServerInformation(se.getFecName());

    al.add("OS  : "+inf.getOs());
    al.add("ver : "+inf.getVer());   
    al.add("fec : "+ se.getFecName());
    String ip = se.getFecAddr().fecHost.getHostAddress().toString();
    al.add("ip  : "+ ip);
    al.add("host: "+ se.getFecAddr().fecHost.getHostName());
   
    TServerSettings tsrvs = TQuery.getServerSettings(tgt);
    //al.add(tsrvs.toString());
   
    if (tsrvs != null)
    {
      al.add("settings :");
      al.add("\tserver working area: "+tsrvs.getSrvWorkArea());
      al.add("\tcontract table capacity: "+tsrvs.getConTblCapacity());
      al.add("\tclient table capacity: "+tsrvs.getClnTblCapacity());
      al.add("\tserver sck recv buffers: "+tsrvs.getSrvRecvBuffers());
      al.add("\tminimum polling interval: "+tsrvs.getMinPollInterval());
      al.add("\tclient-side link capacity: "+tsrvs.getLnkTblCapacity());
      al.add("\tclient-side sck recv buffers: "+tsrvs.getClnRecvBuffers());
    }

    int rc;
    boolean isOffline = false;
    TLink lnk;
    TDataType tdt;
    NAME32[] n32 = new NAME32[100];
    al.add("security :");
    tdt = new TDataType(n32);
    lnk = new TLink(tgt,"USERS",tdt,null,TAccess.CA_READ);   
    rc = lnk.executeAndClose();
    if (rc == TErrorList.link_timeout || rc == TErrorList.connection_timeout)
      isOffline = true;
    if (rc == 0 && tdt.getCompletionLength() > 0)
    {
      al.add("WRITE access open to Users : ");
      for (int i=0; i<tdt.getCompletionLength(); i++)
        al.add("\t"+n32[i].name);
    }
    else
    {
      if (!isOffline) al.add("WRITE access open to : ALL users");
    }
    lnk = new TLink(tgt,"IPNETS",tdt,null,TAccess.CA_READ);   
    rc = isOffline ? TErrorList.connection_timeout : lnk.executeAndClose();
    if (rc == 0 && tdt.getCompletionLength() > 0)
    {
      al.add("WRITE access open to Network Addresses : ");
      for (int i=0; i<tdt.getCompletionLength(); i++)
        al.add("\t"+n32[i].name);
    }
    else
    {
      if (!isOffline) al.add("WRITE access open to : ALL network addresses");
    }
    al.add("servers running on same host :");   
    ServerQuery[] sqhst = TQuery.getDeviceServersEx(context, ip,"ALL");
    for (ServerQuery sq : sqhst) al.add("\t"+sq.getName());

    String[] alst = ENSTools.getServerAliasList(tgt);
    if (alst != null && alst.length > 0)
    {
      al.add("aliases for "+tgt+":");   
      for (String s : alst) al.add("\t"+s+ " -> "+tgt);
    }
    if (!isOffline)
    {
      String[] devs = TQuery.getDeviceNames(context, server);
      if (devs != null)
      {
        al.add(tgt+" has "+devs.length+" devices");
        if (TQuery.devices_have_query_function)
        {
          al.add(tgt+" has property query precedence (classic property server model)");
          tgtdev = "#0";
        }
        if (devs.length > 0 && tgtdev == null) tgtdev = devs[0];
        //for (String s: devs) al.add(s);
      }
   
      String[] prps = TQuery.getDeviceProperties(context, server, tgtdev);
      if (prps != null)
      {
        al.add(tgt+" has "+prps.length+" properties");
        if (TQuery.properties_have_query_function)
        {
          al.add(tgt+" has device query precedence (classic device server model)");
        }
        if (devs.length > 0 && tgtdev == null) tgtdev = devs[0];
        //for (String s: prps) al.add(s);
      }
      TPropertyQuery pztpq[] = null;
      long t0;
      String rdr = null, lclhststr = null;
      int callsOK = 0;
      int callsErr = 0;
      int callsNA = 0;
      int len = prps.length;
      if (limit > 0 && limit < len) len = limit;
      for (int i=0; prps != null && i<len; i++)
      {
        pztpq = TQuery.getPropertyInformation(context, server, tgtdev, prps[i]);
        if (pztpq == null)
        {
          callsErr++;
          continue;
        }
        for (TPropertyQuery p: pztpq)
        {
          if (TAccess.isRead(p.prpAccess))
          {
            al.add("read "+p.prpName+" : "+p.prpDescription);
            lclhststr = p.prpHistoryDepthShort == 0 ? "none" :
                        p.prpHistoryDepthShort < 0 ? "redirected" :
                        p.prpHistoryDepthLong > 0 ? ""+p.prpHistoryDepthLong+" month(s)" :
                        ""+p.prpHistoryDepthShort+" entries in ring buffer";
            al.add("\tlocal history : "+lclhststr);
            al.add("\tarray type : "+TArrayType.toString(p.prpArrayType));
            if (p.prpRedirection.length() > 0)
              al.add("\tis redirected to "+p.prpRedirection);
            if (p.prpSizeIn > 0) al.add("\ttakes input: "+p.prpSizeIn+" "+TFormat.toString(p.prpFormatIn)+" elements");
            al.add("\tresults:");
            if (p.prpFormat == TFormat.CF_STRUCT)
            {
              int ssiz = 0;
              if ((ssiz=TStructRegistry.getSizeInBytes(p.prpTag)) <= 0)
              {
                TQuery.AcquireAndRegisterStructInfo(context, server, p.prpTag);
                ssiz = TStructRegistry.getSizeInBytes(p.prpTag,context,server);
              }
              if (ssiz > 0) tdt = new TDataType(new byte[ssiz],p.prpTag);
              else
              {
                al.add("\tunable to acquire and register structure tag "+p.prpTag);
                tdt = new TDataType(p.prpSize,p.prpFormat);
              }
            }
            else if (p.prpFormat == TFormat.CF_AIMAGE || p.prpFormat == TFormat.CF_ASPECTRUM)
            {
              al.add("\t"+lnk.getFullDeviceNameAndProperty()+" adjustable format not accessed");
              callsNA++;  
              continue;
            }
            else
            {
              tdt = new TDataType(p.prpSize,p.prpFormat);
            }
            lnk = new TLink(tgt+"/"+tgtdev,p.prpName,tdt,null,TAccess.CA_READ);
            t0 = System.currentTimeMillis();
            rc = lnk.executeAndClose();
            if (rc == TErrorList.illegal_read_write && p.prpSizeIn > 0)
            {
              al.add("\t"+lnk.getFullDeviceNameAndProperty()+" not accessed: requires input data");
              callsNA++;
            }
            else
            {
              al.add("\t"+lnk.getFullDeviceNameAndProperty()+" "+p.prpSize+" "+
                TFormat.toString(p.prpFormat)+" value(s) in "+
                (System.currentTimeMillis()-t0)+" ms : "+lnk.getLastError());
              TDataType dout = lnk.getOutputDataObject();
              switch (dout.dFormat)
              {
                case TFormat.CF_STRUCT:
                  al.add("\tStructure type "+dout.getTag());
                  break;
                case TFormat.CF_BITFIELD8:
                case TFormat.CF_BITFIELD16:
                case TFormat.CF_BITFIELD32:
                case TFormat.CF_BITFIELD64:
                  al.add("\tBitfield type "+dout.getTag());
                  break;
                case TFormat.CF_IMAGE:
                  IMAGE img = (IMAGE)dout.getDataObject();
                  al.add("\tImage; Frame size "+img.getFrameHeader().appendedFrameSize+" bytes");
                  break;
                default:
                  if (dout.dCompletionLength <= 10)
                  {
                    dout.setArrayDelimiter(" ");
                    al.add("\tvalues: "+dout.toString());                 
                  }
                  else
                  {
                    al.add("\treceived "+dout.dCompletionLength+" values");
                  }
                  break;
              }
              if (TErrorList.hasData(rc)) callsOK++; else callsErr++;
            }
            if ((rdr=lnk.getRedirectionKey()) != null && rdr.length() > 0)
            {
              al.add("\t"+"redirected to "+rdr);
            }
          }
          else
          {
            al.add("write "+p.prpName+" : "+p.prpDescription);
            if (p.prpRedirection.length() > 0)
              al.add("\tis redirected to "+p.prpRedirection);
            al.add("\tresults:");
            al.add("\t not accessed: is a command!");
            callsNA++;
          }
        }
      }
      al.add("total calls : "+(callsOK+callsErr+callsNA));
      al.add("total succeeded : "+callsOK);
      al.add("total failed : "+callsErr);
      al.add("total not accessed : "+callsNA);
    }
    else
    {
      al.add("server appears to be offline");
    }
   
    return al.toArray(new String[0]);
  }
  /**
   * Returns a list of device servers associated with the specified
   * context (obtained from the name services)
   *
   * @param context Is the context for which the device server name list is
   * desired
   *
   * @return A string array containing a list of device servers associated
   * with the given context as obtained from the Equipment Name Server (ENS)
   * A null pointer is returned if the call fails for any reason. 
   */
  public static String[] getDeviceServers(String context)
  {
    String[] lst = getTagList(context,"TAGS");
    if (lst != null) return lst;
    // then try static cache:
    return DBQuery.getServersFromFileCache(context,null);
  }
  /**
   * Returns a list of device servers associated with the specified
   * context and subsystem (obtained from the name services)
   *
   * @param context Is the context for which the device server name list is
   * desired
   * @param subsys Is the subsystem for which the device server name list is
   * desired
   *
   * @return A string array containing a list of device servers associated
   * with the given context and subsystem as obtained from the Equipment Name Server (ENS)
   * A null pointer is returned if the call fails for any reason. 
   */
  public static String[] getDeviceServers(String context,String subsys)
  {
    if (!TLinkFactory.getInstance().isRunningStandAlone())
    {
      String[] lst = getTagList(context,"TAGS",subsys);
      if (lst != null) return lst;
    }
    // then try static cache:
    return DBQuery.getServersFromFileCache(context,subsys);
  }
  /**
   * Returns a list of device servers associated with the specified
   * context, subsystem, and importance level (obtained from the name services)
   *
   * @param context Is the context for which the device server name list is
   * desired
   * @param subsys Is the subsystem for which the device server name list is
   * desired
   * @param imporance Is the importance level for which the device server name list is
   * desired (one of "ALL", "IMPORTANT", "ESSENTIAL", or "CRITICAL")
   *
   * @return A ServerQuery array containing a list of device servers associated
   * with the given context, subsystem, and importance as obtained from the
   * Equipment Name Server (ENS)
   * A null pointer is returned if the call fails for any reason. 
   */
  public static ServerQuery[] getDeviceServersEx(String context,String subsys,String importance)
  {
    return getDeviceServersEx(context,subsys,importance,TLink.defaultTimeout);
  }
  /**
   * Returns a list of device servers associated with the specified
   * context, subsystem, and importance level (obtained from the name services)
   *
   * @param context Is the context for which the device server name list is
   * desired
   * @param subsys Is the subsystem for which the device server name list is
   * desired
   * @param imporance Is the importance level for which the device server name list is
   * desired (one of "ALL", "IMPORTANT", "ESSENTIAL", or "CRITICAL")
   * @param timeout is the time in milliseconds to wait for the call to complete
   *
   * @return A ServerQuery array containing a list of device servers associated
   * with the given context, subsystem, and importance as obtained from the
   * Equipment Name Server (ENS)
   * A null pointer is returned if the call fails for any reason. 
   */
  public static ServerQuery[] getDeviceServersEx(String context,String subsys,String importance,int timeout)
  {
    return getXTagList(context,"TAGS",subsys,importance,timeout);
  }
  /**
   * Returns a list of registered subsystems
   * (obtained from the name services)
   *
   * @return A string array containing a list of subsystems.
   * The subsystem is itself not part of the TINE name space,
   * but can be used to refine queries to the Equipment Name
   * Servers (ENS).
   * A null pointer is returned if the call fails for any reason. 
   */
  public static String[] getDeviceSubsystems()
  {
    String[] lst = getTagList(null,"SUBSYSTEMS");
    if (lst != null) return lst;
    return DBQuery.getSubsystemsFromFileCache(null);
  }
  /**
   * Returns a list of registered subsystems in a given context
   * (obtained from the name services)
   *
   * @param context Is the context for which the subsystem list is desired
   *
   * @return A string array containing a list of available subsystems in the given context.
   * The subsystem is itself not part of the name space,
   * but can be used to refine queries to the Equipment Name
   * Servers (ENS).
   * A null pointer is returned if the call fails for any reason. 
   */
  public static String[] getDeviceSubsystems(String context)
  {
    if (!TLinkFactory.getInstance().isRunningStandAlone())
    {
      String[] lst = getTagList(context,"SUBSYSTEMS");
      if (lst != null) return lst;
    }
    return DBQuery.getSubsystemsFromFileCache(context);
  }
  /**
   * Returns a list of front end computers (FECs) associated with the specified
   * context (obtained from the name services)
   *
   * @param context Is the context for which the FEC name list is
   * desired
   *
   * @return A string array containing a list of front end computers associated
   * with the given context as obtained from the Equipment Name Server (ENS)
   * A null pointer is returned if the call fails for any reason. 
   */
  public static String[] getServers(String context)
  {
    return getTagList(context,"FECS");
  }
  /**
   * Returns a list of front end computers (FECs) associated with the specified
   * context and sub system (obtained from the name services)
   *
   * @param context Is the context for which the FEC name list is
   * desired
   * @param subsys Is the subsystem for which the device server name list is
   * desired
   *
   * @return A string array containing a list of front end computers associated
   * with the given context and subsystem as obtained from the Equipment Name Server (ENS)
   * A null pointer is returned if the call fails for any reason. 
   */
  public static String[] getServers(String context,String subsys)
  {
    return getTagList(context,"FECS",subsys);
  }
  public static String[] getServersOnFec(String fecname)
  {
    return getTagList("DEFAULT","TAGS",fecname);
  }
  /**
   * Returns a list of front end computers (FECs) associated with the specified
   * context, subsystem, and importance level (obtained from the name services)
   *
   * @param context Is the context for which the device server name list is
   * desired
   * @param subsys Is the subsystem for which the device server name list is
   * desired
   * @param imporance Is the importance level for which the device server name list is
   * desired (one of "ALL", "IMPORTANT", "ESSENTIAL", or "CRITICAL")
   *
   * @return A ServerQuery array containing a list of device servers associated
   * with the given context, subsystem, and importance as obtained from the
   * Equipment Name Server (ENS)
   * A null pointer is returned if the call fails for any reason. 
   */
  public static ServerQuery[] getServersEx(String context,String subsys,String importance)
  {
    return getServersEx(context,subsys,importance,TLink.defaultTimeout);
  }
  /**
   * Returns a list of front end computers (FECs) associated with the specified
   * context, subsystem, and importance level (obtained from the name services)
   *
   * @param context Is the context for which the device server name list is
   * desired
   * @param subsys Is the subsystem for which the device server name list is
   * desired
   * @param imporance Is the importance level for which the device server name list is
   * desired (one of "ALL", "IMPORTANT", "ESSENTIAL", or "CRITICAL")
   * @param timeout is the time in milliseconds to wait for completion.
   *
   * @return A ServerQuery array containing a list of device servers associated
   * with the given context, subsystem, and importance as obtained from the
   * Equipment Name Server (ENS)
   * A null pointer is returned if the call fails for any reason. 
   */
  public static ServerQuery[] getServersEx(String context,String subsys,String importance,int timeout)
  {
    return getXTagList(context,"FECS",subsys,importance,timeout);
  }
  /**
   * @param fullServerName is the fully specified device server for which the
   * information is requested (/<context>/<server>).
   *
   * @return an array of TClientStruct objects containing information
   * about each of the clients attached to the targeted server.
   * Returns null if the information cannot be obtained.
   */
  public static TClientStruct[] getServerClients(String fullServerName)
  {
    if (fullServerName == null) return null;
    TClientStruct[] tcs = new TClientStruct[100];
    for (int i=0; i<100; i++) tcs[i] = new TClientStruct();
    TDataType tcsd = new TDataType(tcs);
    TLink tl = new TLink(fullServerName,"CLIENTS",tcsd,null,TAccess.CA_READ);
    if (tl.executeAndClose(TLink.defaultTimeout) == 0)
    {
      int len;
      for (len=0; len<100 && tcs[len].getProtocol()[0] != (short)0; len++);
      if (len < 100)
      {
        TClientStruct[] tcss = new TClientStruct[len];
        System.arraycopy(tcs,0,tcss,0,len);
        return tcss;
      }
      return tcs;
    }
    DbgLog.log("getServerClients","error : " + tl.linkStatus);
    return null;
  }
  public static TContractStruct[] getServerContracts(String fullServerName)
  {
    if (fullServerName == null) return null;
    TContractStruct[] tcs = new TContractStruct[100];
    for (int i=0; i<100; i++) tcs[i] = new TContractStruct();
    TDataType tcsd = new TDataType(tcs);
    TLink tl = new TLink(fullServerName,"CONTRACTS",tcsd,null,TAccess.CA_READ);
    if (tl.executeAndClose(TLink.defaultTimeout) == 0)
    {
      int len;
      for (len=0; len<100 && tcs[len].getEqpProperty()[0] != (char)0; len++);
      if (len < 100)
      {
        TContractStruct[] tcss = new TContractStruct[len];
        System.arraycopy(tcs,0,tcss,0,len);
        return tcss;
      }
      return tcs;
    }
    DbgLog.log("getServerContracts","error : " + tl.linkStatus);
    return null;
  }
  public static TServerSettings getServerSettings(String fullServerName)
  {
    if (fullServerName == null) return null;
    TServerSettings[] tss = new TServerSettings[1];
    tss[0] = new TServerSettings();
    TDataType tssd = new TDataType(tss);
    TLink tl = new TLink(fullServerName,"SRVSETTINGS",tssd,null,TAccess.CA_READ);
    if (tl.executeAndClose(TLink.defaultTimeout) == 0)
    {
      return tss[0];
    }
    DbgLog.log("getServerSettings","error : " + tl.linkStatus);
    return null;
  }
  public static TWriteAccessInfo[] getServerCommandList(String fullServerName)
  {
    if (fullServerName == null) return null;
    TWriteAccessInfo[] twai = new TWriteAccessInfo[100];
    for (int i=0; i<100; i++) twai[i] = new TWriteAccessInfo();
    TDataType d = new TDataType(twai);
    TLink tl = new TLink(fullServerName,"SRVCOMMANDS",d,null,TAccess.CA_READ);
    if (tl.executeAndClose(TLink.defaultTimeout) == 0)
    {
      int len = d.getCompletionLength();
      TWriteAccessInfo[] ra = (len < 100) ? Arrays.copyOf(twai, len) : twai;
      return ra;
    }
    DbgLog.log("getServerCommandList","error : " + tl.linkStatus);
    return null;
  }
  private static final int FECINFO_BASESIZE = 208;
  /**
   * Retrieves information about the specified front-end computer.
   * @param frontEndComputer
   * @return a FECInfo object containing the front end computer information.
   * If the information cannot be obtained for what ever reason, the FECInfo
   * object will contain nothing but "unknown" strings.
   */
  public static FECInfo getServerInformation(String frontEndComputer)
  {
    TFecEntry fec;
    FECInfo info;
    if (frontEndComputer == null) return null;
    if ((fec=TSrvEntry.getFecEntry(frontEndComputer)) != null)
    {
      if (fec.info != null) return fec.info;
    }
    String os, desc, loc, hdw, ver, resp;
    char[] fi = new char[FECINFO_BASESIZE];
    TDataType fid = new TDataType(fi);
    if (frontEndComputer.startsWith("ENS#")) frontEndComputer = "ENS";
    TLink tl = new TLink("ENS/FEC.EXT",frontEndComputer,fid,null,TAccess.CA_READ);
    if (tl.executeAndClose(TLink.defaultTimeout) == 0)
    {
      int off = 0;
      os = new String(fi,off,TStrings.FEC_OS_SIZE); off += TStrings.FEC_OS_SIZE;
      desc = new String(fi,off,TStrings.FEC_DESC_SIZE); off += TStrings.FEC_DESC_SIZE;
      loc = new String(fi,off,TStrings.FEC_LOCATION_SIZE); off += TStrings.FEC_LOCATION_SIZE;
      ver = new String(fi,off,TStrings.FEC_VERSION_SIZE); off += TStrings.FEC_VERSION_SIZE;
      hdw = new String(fi,off,TStrings.FEC_HDW_SIZE); off += TStrings.FEC_HDW_SIZE;
      resp = new String(fi,off,TStrings.FEC_RESP_SIZE); off += TStrings.FEC_RESP_SIZE;
      // parse away legacy description info
      if (desc.startsWith("["))
      {
        int p = desc.indexOf(']');
        if (p != -1)
        {
          desc = desc.substring(p+1);
        }
      }
    }
    else
    {
      os = "unknown"; desc = "unknown"; loc = "unknown";
      hdw = "unknown"; ver = "unknown"; resp = "unknown";
    }
    info = new FECInfo(os,desc,loc,hdw,ver,resp);
    if (fec != null) fec.info = info;
    return info;
  }
  /**
   * Returns a list of properties associated with the specified
   * context and device server and device (obtained from the device server)
   *
   * @param context Is the context of the device server for which the property list is
   * desired.
   * @param server Is the device server for which the property list is
   * desired.
   * @param device Is the device name (module name) for which the property list
   * is desired.
   *
   * @return A string array containing a list of properties
   * as obtained from the given device server
   */
  public static String[] getDeviceProperties(String context,String server,String device)
  {
    return getDeviceProperties(context,server,device,TLink.defaultTimeout);
  }
  public static String[] getDeviceProperties(String context,String server,String device,int timeout)
  {
    return getDeviceProperties(context,server,device,null,timeout);
  }
  /**
   * Returns a list of properties associated with the specified
   * context and device server, device, and property (sub)string
   * (obtained from the device server)
   *
   * @param context Is the context of the device server for which the property list is
   * desired.
   * @param server Is the device server for which the property list is
   * desired.
   * @param device Is the device name (module name) for which the property list
   * is desired.
   * @param property Can be a queriable string with wildcard
   * parameter '*'.  e.g. property = 'P*' will return all properties whose
   * first letter begins with 'P'.
   *
   * @return A string array containing a list of properties
   * as obtained from the given device server
   * A null pointer is returned if the call fails for any reason. 
   */
  public static String[] getDeviceProperties(String context,String server,String device,String property)
  {
    return getDeviceProperties(context,server,device,property,TLink.defaultTimeout);
  }
  /**
   * Returns a list of properties associated with the specified
   * context and device server, device, and property (sub)string
   * (obtained from the device server)
   *
   * @param context Is the context of the device server for which the property list is
   * desired.
   * @param server Is the device server for which the property list is
   * desired.
   * @param device Is the device name (module name) for which the property list
   * is desired.
   * @param property Can be a queriable string with wildcard
   * parameter '*'.  e.g. property = 'P*' will return all properties whose
   * first letter begins with 'P'.
   * @param timeout is the time in milliseconds to allow the call to complete
   *
   * @return A string array containing a list of properties
   * as obtained from the given device server
   * A null pointer is returned if the call fails for any reason. 
   */
  public static String[] getDeviceProperties(String context,String server,String device,String property,int timeout)
  {
    String[] prps = null;
    try
    {
      prps = getDeviceProperties64(context,server,device,property,timeout);
      if (prps != null) return prps;
      prps = getDeviceProperties16(context,server,device,property,timeout);
    }
    catch (IOException e)
    {
      return null;
    }
    return prps;
  }
  private static String[] getDeviceProperties16(String context,String server,String device,String property,int timeout) throws IOException
  {
    String tgt = getNamesQueryTarget(context,server,device);
    if (tgt == null) return null;
    TLink tl;
    TDataType dout;
    TDataType din;
    int cc = 0,n,i,j;
    NAME32[] properties;
    String[] strprops;

    n = getNumberOf("PROPS",tgt);
    if (n <= 0) return null;
    if (n*32 > maxQueryBufferSize) n = maxQueryBufferSize/32;
    properties = new NAME32[n];
    for (i=0; i<n; i++) properties[i] = new NAME32();
    if (properties.length <= 0) return null;
    dout = new TDataType(properties);
    if (property != null) din = new TDataType(property); else din = null;
    properties_have_query_function = false;
    try
    {
      tl = new TLink(tgt,"PROPS",dout,din,TAccess.CA_READ);
      cc = tl.execute(TLink.defaultTimeout,true);
      tl.close();
      if ((cc & TErrorList.CE_SENDDATA) == TErrorList.CE_SENDDATA)
      {
        if ((cc & TErrorList.has_query_function) == TErrorList.has_query_function)
        {
          properties_have_query_function = true;
        }
        cc = 0;
      }
    }
    catch (Exception e)
    {
      MsgLog.log("getDeviceProperties16", e.getMessage(),TErrorList.non_existent_elem,e,0);
      cc = TErrorList.host_not_resolved;
    }
    if (cc == 0)
    {
      for (i=0,n=0; i<properties.length; i++) if (properties[i].name.length() > 0) n++;
      strprops = new String[n];
      for (i=0,j=0; j<n && i<properties.length; i++)
      {
        if (properties[i].name.length() == 0) continue;
        strprops[j++] = properties[i].name;
      }
      return strprops;
    }
    else if (cc != TErrorList.link_not_open)
    {
      if (lastQueriedContext == context && lastQueriedServer == server &&
          lastQueriedDevice == device && lastQueriedServer != null)
      {
        cc = 0;
      }
      else
      {
        hLegacyByteBlob = new byte[n * PropertyQuery.sizeInBytes];
        dout = new TDataType(hLegacyByteBlob,"");
        tl = new TLink(tgt,"PROPS",dout,din,TAccess.CA_READ);
        cc = tl.execute(TLink.defaultTimeout,false);
        tl.close();
      }
      if (cc == 0)
      {
        lastQueriedContext = context;
        lastQueriedServer = server;
        lastQueriedDevice = device;
        strprops = new String[n];
        PropertyQuery[] pq = new PropertyQuery[n];
        byte b[];
        if (hLegacyByteBlob == null) return null;
        for (i=0; i<n; i++)
        {
          pq[i] = new PropertyQuery();
          b = pq[i].toByteArray();
          System.arraycopy(hLegacyByteBlob,i*PropertyQuery.sizeInBytes,b,0,PropertyQuery.sizeInBytes);
          pq[i].toStruct();
          strprops[i] = pq[i].name;
        }       
        return strprops;
      }
    }
    throw new IOException("Could not acquire property information for " + server + " (" + TErrorList.getErrorString(cc) + ")");
  }
  /**
   * Returns an array of properties matching the pattern input
   *
   * @param context is the desired server context
   * @param server is the targeted device server
   * @param device is the targeted device name
   * @param propertyPattern is the property pattern (using the wild card character '*')
   * for which a match is desired.
   * @param timeout is the time in milliseconds to allow the call to complete.
   * @return a string array containing those properties which match the pattern given.
   * @throws IOException
   */
  public static String[] getPropertiesWithPattern(String context,String server,String device,String propertyPattern,int timeout) throws IOException
  {
    String tgt = getNamesQueryTarget(context,server,device);
    if (tgt == null || propertyPattern == null) return null;
    TLink tl;
    TDataType dout;
    int cc = 0,n = 64,i,j;
    NAME64[] properties;
    String[] strprops;
    properties = new NAME64[n];
    for (i=0; i<n; i++) properties[i] = new NAME64();
    dout = new TDataType(properties);
    try
    {     
      tl = new TLink(tgt,propertyPattern,dout,null,TAccess.CA_READ);
      cc = tl.execute(timeout,true);
      tl.close();
      if ((cc & TErrorList.CE_SENDDATA) == TErrorList.CE_SENDDATA)
      {
        cc = 0;
      }
    }
    catch (Exception e)
    {
      MsgLog.log("getPropertiesWithPattern", e.getMessage(),TErrorList.non_existent_elem,e,0);
      cc = TErrorList.non_existent_elem;
    }
    if (cc == TErrorList.illegal_format) return null; // legacy server
    if (cc == 0)
    {
      n = dout.getCompletionLength();
      strprops = new String[n];
      for (i=0,j=0; j<n && i<properties.length; i++)
      {
        if (properties[i].name.length() == 0) continue;
        strprops[j++] = properties[i].name;
      }
      return strprops;
    }
    throw new IOException("Could not acquire property information for " + server + " (" + TErrorList.getErrorString(cc) + ")");   
  }
  private static String[] getDeviceProperties64(String context,String server,String device,String property,int timeout) throws IOException
  {
    String tgt = getNamesQueryTarget(context,server,device);
    if (tgt == null) return null;
    TLink tl;
    TDataType dout;
    TDataType din;
    int cc = 0,n,i,j;
    NAME64[] properties;
    String[] strprops;

    n = getNumberOf("PROPS",tgt);
    if (n == -TErrorList.illegal_device_number)
    { // a Steve special ...
      strprops = new String[1];
      strprops[0] = "INVALID";
      properties_have_query_function = true;
      return strprops;
    }
    if (n <= 0) return null;
    if (n < 128) n = 256; else n += 100; // room for aliases
    if (n*32 > maxQueryBufferSize) n = maxQueryBufferSize/64;
    properties = new NAME64[n];
    for (i=0; i<n; i++) properties[i] = new NAME64();
    if (properties.length <= 0) return null;
    dout = new TDataType(properties);
    if (property != null) din = new TDataType(property); else din = null;
    properties_have_query_function = false;
    try
    {
      tl = new TLink(tgt,"PROPS",dout,din,TAccess.CA_READ);
      cc = tl.execute(TLink.defaultTimeout,true);
      tl.close();
      if ((cc & TErrorList.CE_SENDDATA) == TErrorList.CE_SENDDATA)
      {
        if ((cc & TErrorList.has_query_function) == TErrorList.has_query_function)
        {
          properties_have_query_function = true;
        }
        cc = 0;
      }
      if (cc == TErrorList.illegal_device_number)
      { // try this
        properties_have_query_function = true;
      }
    }
    catch (Exception e)
    {
      MsgLog.log("getDeviceProperties64", e.getMessage(),TErrorList.non_existent_elem,e,0);
      cc = TErrorList.host_not_resolved;
    }
    if (cc == TErrorList.illegal_format ||
        cc == TErrorList.invalid_transport_size) return null; // legacy server
    if (cc == 0)
    {
      if (properties[0].name.length() == 0) return null; // release 3.3 java problem
      for (i=0,n=0; i<properties.length; i++) if (properties[i].name.length() > 0) n++;
      strprops = new String[n];
      for (i=0,j=0; j<n && i<properties.length; i++)
      {
        if (properties[i].name.length() == 0) continue;
        strprops[j++] = properties[i].name;
      }
      return strprops;
    }
    throw new IOException("Could not acquire property information for " + server + " (" + TErrorList.getErrorString(cc) + ")");
  }
  private static String getTineStockString(String context,String server,String property,String text)
  {
    TLink tl;
    TDataType dout;
    String tgt;
    int cc = 0;
    StringBuffer ver = new StringBuffer(32);
 
    tgt = new String("/" + context + "/" + server + "/#0");
    dout = new TDataType(ver);
    try
    {
      tl = new TLink(tgt,property,dout,null,TAccess.CA_READ);
      cc = tl.execute(TLink.defaultTimeout,true);
      tl.close();
    }
    catch (Exception e)
    {
      MsgLog.log("getTineStockString", e.getMessage(),TErrorList.non_existent_elem,e,0);
      cc = TErrorList.non_existent_elem;
    }
    if (cc == 0)
    {
      return text + " : " + ver.toString().trim();
    }
    return text + " : unavailable";
  }
  /**
   * Retrieves the TINE version of the input server
   *
   * @param context is the desired context
   * @param server is the targeted server
   * @return the current TINE version of the specified server
   */
  public static String getTineVersion(String context,String server)
  {
    return getTineStockString(context,server,"SRVVERSION","tine version");
  }
  /**
   * Retrieves the application version of the input server
   *
   * @param context is the desired context
   * @param server is the targeted server
   * @return the current application version of the specified server.
   * If this information is not supplied by the server developer,
   * then "1.0.0" will be the likely result. 
   */
  public static String getAppVersion(String context,String server)
  {
    return getTineStockString(context,server,"APPVERSION","Appl version");
  }
  /**
   * Retrieves the application compile date
   *
   * @param context is the desired context
   * @param server is the targeted server
   * @return the current application compile data of the specified server.
   * If this information is not supplied by the server developer,
   * then "January 1, 1970" will be the likely result. 
   */
  public static String getAppDate(String context,String server)
  {
    return getTineStockString(context,server,"APPDATE","Appl date");
  }
  /**
   * Returns a list of stock properties associated with the specified
   * context and device server (obtained from the device server).
   *
   * @param context Is the context of the device server for which the property list is
   * desired.
   * @param server Is the device server for which the property list is
   * desired.
   *
   * @return A string array containing a list of stock properties
   * as obtained from the given device server
   */
  public static String[] getStockProperties(String context,String server)
  {
    return getStockProperties(context,server,"#0",null);
  }
  /**
   * Returns a list of stock properties associated with the specified
   * context and device server, device, and property (sub)string
   * (obtained from the device server).  Typically, the device parameter does not
   * play a role in this query.
   *
   * @param context Is the context of the device server for which the property list is
   * desired.
   * @param server Is the device server for which the property list is
   * desired.
   * @param device Is the device name (module name) for which the property list
   * is desired.
   * @param property Can be a queriable string with wildcard
   * parameter '*'.  e.g. property = 'P*' will return all stock properties whose
   * first letter begins with 'P'.
   *
   * @return A string array containing a list of stock properties
   * as obtained from the given device server
   */
  public static String[] getStockProperties(String context,String server,String device,String property)
  {
    TLink tl;
    TDataType dout;
    TDataType din;
    String tgt;
    int cc = 0,n = 0,i,j;
    NAME32[] properties;
    String[] strprops;

    tgt = new String("/" + context + "/" + server + "/" + device);
    try
    {
      n = getNumberOf("STOCKPROPS",tgt);
    }
    catch (IOException e)
    {
      return null;
    }
    if (n <= 0) return null;
    if (n*32 > maxQueryBufferSize) n = maxQueryBufferSize/32;
    properties = new NAME32[n];
    for (i=0; i<n; i++) properties[i] = new NAME32();
    dout = new TDataType(properties);
    if (property != null) din = new TDataType(property); else din = null;
    properties_have_query_function = false;
    tl = new TLink(tgt,"STOCKPROPS",dout,din,TAccess.CA_READ);
    cc = tl.execute(TLink.defaultTimeout,true);
    if ((cc & TErrorList.CE_SENDDATA) == TErrorList.CE_SENDDATA)
    {
      if ((cc & TErrorList.has_query_function) == TErrorList.has_query_function)
      {
        properties_have_query_function = true;
      }
      cc = 0;
    }
    tl.close();
    if (cc == 0)
    {
      for (i=0,n=0; i<properties.length; i++) if (properties[i].name.length() > 0) n++;
      strprops = new String[n];
      for (i=0,j=0; j<n && i<properties.length; i++)
      {
        if (properties[i].name.length() == 0) continue;
        strprops[j++] = properties[i].name;
      }
      return strprops;
    }
    else if (cc != TErrorList.link_not_open)
    {
      if (lastQueriedContext == context && lastQueriedServer == server &&
          lastQueriedDevice == device && lastQueriedServer != null)
      {
        cc = 0;
      }
      else
      {
        hLegacyByteBlob = new byte[n * PropertyQuery.sizeInBytes];
        dout = new TDataType(hLegacyByteBlob,"");
        tl = new TLink(tgt,"STOCKPROPS",dout,din,TAccess.CA_READ);
        cc = tl.execute(TLink.defaultTimeout,false);
        tl.close();
      }
      if (cc == 0)
      {
        lastQueriedContext = context;
        lastQueriedServer = server;
        lastQueriedDevice = device;
        strprops = new String[n];
        PropertyQuery[] pq = new PropertyQuery[n];
        byte b[];
        if (hLegacyByteBlob == null) return null;
        for (i=0; i<n; i++)
        {
          pq[i] = new PropertyQuery();
          b = pq[i].toByteArray();
          System.arraycopy(hLegacyByteBlob,i*PropertyQuery.sizeInBytes,b,0,PropertyQuery.sizeInBytes);
          pq[i].toStruct();
          strprops[i] = pq[i].name;
        }       
        return strprops;
      }
    }
    MsgLog.log("TQuery.getStockProperties", "Could not acquire property information for " + server,cc,null,0);
    return null;
  }
  /**
   * Returns a list of meta properties associated with the specified
   * context and device server (obtained from the device server).
   *
   * @param context Is the context of the device server for which the property list is
   * desired.
   * @param server Is the device server for which the property list is
   * desired.
   *
   * @return A string array containing a list of meta properties
   * as obtained from the given device server
   */
  public static String[] getMetaProperties(String context,String server)
  {
    return getMetaProperties(context,server,"#0",null);
  }
  /**
   * Returns a list of meta properties associated with the specified
   * context and device server, device, and property (sub)string
   * (obtained from the device server).  Typically, the device parameter does not
   * play a role in this query.
   *
   * @param context Is the context of the device server for which the property list is
   * desired.
   * @param server Is the device server for which the property list is
   * desired.
   * @param device Is the device name (module name) for which the property list
   * is desired.
   * @param property Can be a queriable string with wildcard
   * parameter '*'.  e.g. property = 'P*' will return all stock properties whose
   * first letter begins with 'P'.
   *
   * @return A string array containing a list of meta properties
   * as obtained from the given device server
   */
  public static String[] getMetaProperties(String context,String server,String device,String property)
  {
    TLink tl;
    TDataType dout;
    TDataType din;
    String tgt;
    int cc = 0,n = 0,i,j;
    NAME64[] properties;
    String[] strprops;

    tgt = new String("/" + context + "/" + server + "/" + device);
    try
    {
      TPropertyQuery[] pq = getStockPropertyInformation(context,server,device,"METAPROPS");
      if (pq != null) {
        n = pq[0].prpSize;
      }
    }
    catch (Exception e)
    {
      return null;
    }
    if (n <= 0) return null;
    if (n*32 > maxQueryBufferSize) n = maxQueryBufferSize/32;
    properties = new NAME64[n];
    for (i=0; i<n; i++) properties[i] = new NAME64();
    dout = new TDataType(properties);
    if (property != null) din = new TDataType(property); else din = null;
    properties_have_query_function = false;
    tl = new TLink(tgt,"METAPROPS",dout,din,TAccess.CA_READ);
    cc = tl.execute(TLink.defaultTimeout,true);
    if ((cc & TErrorList.CE_SENDDATA) == TErrorList.CE_SENDDATA)
    {
      if ((cc & TErrorList.has_query_function) == TErrorList.has_query_function)
      {
        properties_have_query_function = true;
      }
      cc = 0;
    }
    tl.close();
    if (cc == 0)
    {
      for (i=0,n=0; i<properties.length; i++) if (properties[i].name.length() > 0) n++;
      strprops = new String[n];
      for (i=0,j=0; j<n && i<properties.length; i++)
      {
        if (properties[i].name.length() == 0) continue;
        strprops[j++] = properties[i].name;
      }
      return strprops;
    }
    else if (cc != TErrorList.link_not_open)
    {
      if (lastQueriedContext == context && lastQueriedServer == server &&
          lastQueriedDevice == device && lastQueriedServer != null)
      {
        cc = 0;
      }
      else
      {
        hLegacyByteBlob = new byte[n * PropertyQuery.sizeInBytes];
        dout = new TDataType(hLegacyByteBlob,"");
        tl = new TLink(tgt,"METAPROPS",dout,din,TAccess.CA_READ);
        cc = tl.execute(TLink.defaultTimeout,false);
        tl.close();
      }
      if (cc == 0)
      {
        lastQueriedContext = context;
        lastQueriedServer = server;
        lastQueriedDevice = device;
        strprops = new String[n];
        PropertyQuery[] pq = new PropertyQuery[n];
        byte b[];
        if (hLegacyByteBlob == null) return null;
        for (i=0; i<n; i++)
        {
          pq[i] = new PropertyQuery();
          b = pq[i].toByteArray();
          System.arraycopy(hLegacyByteBlob,i*PropertyQuery.sizeInBytes,b,0,PropertyQuery.sizeInBytes);
          pq[i].toStruct();
          strprops[i] = pq[i].name;
        }       
        return strprops;
      }
    }
    MsgLog.log("TQuery.getMetaProperties", "Could not acquire property information for " + server,cc,null,0);
    return null;
  }
  /**
   * Returns a list of device names associated with the specified
   * context and device server
   * (obtained from the device server)
   *
   * As the call is directed to the device server, it assumes the return
   * list applies to all properties
   * 
   * @param context Is the context of the device server for which the property list is
   * desired.
   * @param server Is the device server for which the property list is
   * desired.
   *
   * @return A string array containing a list of devices
   * as obtained from the given device server. 
   * A null pointer is returned if the call fails for any reason. 
   */
  public static String[] getDeviceNames(String context,String server)
  {
    return getDeviceNames(context,server,null);
  }
  /**
   * Returns a list of device names associated with the specified
   * context, device server and property
   * (obtained from the device server)
   *
   * @param context Is the context of the device server for which the device list is
   * desired.
   * @param server Is the device server for which the device list is
   * desired.
   * @param property Is the property for which the device list is
   * desired.
   *
   * @return A string array containing a list of devices
   * as obtained from the given device server
   * A null pointer is returned if the call fails for any reason. 
   */
  public static String[] getDeviceNames(String context,String server,String property)
  {
    return getDeviceNames(context,server,property,TLink.defaultTimeout);
  }
  /**
   * Returns a list of device names associated with the specified
   * context, device server and property
   * (obtained from the device server)
   *
   * @param context Is the context of the device server for which the device list is
   * desired.
   * @param server Is the device server for which the device list is
   * desired.
   * @param property Is the property for which the device list is
   * desired.
   * @param filter is a device name filter containing the wildcard character '*'
   *
   * @return A string array containing a list of devices
   * as obtained from the given device server
   * A null pointer is returned if the call fails for any reason. 
   */
  public static String[] getDeviceNames(String context,String server,String property,String filter)
  {
    return getDeviceNames(context,server,property,filter,TLink.defaultTimeout);
  }
  /**
   * Returns a list of device names associated with the specified
   * context, device server and property
   * (obtained from the device server)
   *
   * @param context is the context of the device server for which the device list is
   * desired.
   * @param server is the device server for which the device list is
   * desired.
   * @param property is the property for which the device list is
   * desired.
   * @param timeout is the time in milliseconds to wait for the call to complete
   *
   * @return A string array containing a list of devices
   * as obtained from the given device server
   * A null pointer is returned if the call fails for any reason. 
   */
  public static String[] getDeviceNames(String context,String server,String property,int timeout)
  {
    return getDeviceNames(context,server,property,null,timeout);
  }
  /**
   * Returns a list of device names associated with the specified
   * context, device server and property
   * (obtained from the device server)
   *
   * @param context is the context of the device server for which the device list is
   * desired.
   * @param server is the device server for which the device list is
   * desired.
   * @param property is the property for which the device list is
   * desired.
   * @param filter is a device name filter containing the wildcard character '*'
   * @param timeout is the time in milliseconds to wait for the call to complete
   *
   * @return A string array containing a list of devices
   * as obtained from the given device server
   * A null pointer is returned if the call fails for any reason. 
   */
  public static String[] getDeviceNames(String context,String server,String property,String filter,int timeout)
  {
    String[] devs = null;
    try
    {
      devs = getDeviceNames64(context,server,property,filter,timeout);
      if (devs != null) return devs;
      devs = getDeviceNames16(context,server,property,timeout);
    }
    catch (IOException e)
    {
      return null;
    }   
    return devs;
  }
  private static String[] getDeviceNames16(String context,String server,String property,int timeout) throws IOException
  {
    DeviceNamesQueryParams dnqp = getDeviceNamesQueryProperty(context,server,property,null,timeout);
    if (dnqp == null) return null;
    int n = dnqp.size;

    TLink tl;
    TDataType dout;
    int cc = 0,i,j;
    String tmp;
    NAME16[] devices;
    String[] strdevs;

    //if (n*16 > maxQueryBufferSize) n = maxQueryBufferSize/16;
    devices = new NAME16[n];
    for (i=0; i<n; i++) devices[i] = new NAME16();
    if (devices.length == 0) return null;
    if (n == 1)
    { // server claimed not to have device names ?
      devices[0].name = "#0";
    }
    dout = new TDataType(devices);
    tl = new TLink(dnqp.target,dnqp.property,dout,null,TAccess.CA_READ);
    cc = tl.execute(timeout,true);
    tl.close();
   
    if ((cc & TErrorList.CE_SENDDATA) == TErrorList.CE_SENDDATA)
    {
      if ((cc & TErrorList.has_query_function) == TErrorList.has_query_function)
      {
        devices_have_query_function = true;
      }
      cc = 0;
    }
    if (cc != 0) return null;
    // check for long names (the Channel Access kluge)
    for (i=0,n=0; i<devices.length; i++)
      if (devices[i].name.length() > 0 && !devices[i].name.endsWith("&")) n++;
    strdevs = new String[n];
    for (i=0,j=0; i<devices.length && j<n; i++)
    {
      tmp = devices[i].name;
      if (tmp.length() == 0) continue;
      if (tmp.endsWith("&"))
      {
        i++;
        tmp = tmp.substring(0, tmp.length() - 1) + devices[i].name;
      }
      strdevs[j++] = tmp;
    }
    return strdevs;
  }
  private static String getNamesQueryTarget(String context,String server,String device)
  {
    String tgt, dev;
    if (server == null || server.length() == 0) return null;
    dev = (device == null) ? "#0" : device; // a '*' here is lethal at the moment !
    if (context == null || context.length() == 0)
      tgt = new String("/DEFAULT/" + server + "/" + dev);
    else
      tgt = new String("/" + context + "/" + server + "/" + dev);
    return tgt;
  }
  private class DeviceNamesQueryParams
  {
    String target;
    String property;
    int size;
  }
  private static TQuery tQueryInstance = new TQuery();
  private static TQuery getInstance()
  {
    if (tQueryInstance == null) tQueryInstance = new TQuery();
    return tQueryInstance;
  }
  private static DeviceNamesQueryParams getDeviceNamesQueryProperty(String context,String server,String property,String filter,int timeout) throws IOException
  {
    if (property != null) filter = null;
    TQuery tq = getInstance();
    String tgt = getNamesQueryTarget(context,server,filter);
    if (tgt == null) return null;
    DeviceNamesQueryParams dnqp = tq.new DeviceNamesQueryParams();
    int n = 0;
    String prp=null;
    TPropertyQuery[] tpq;
    n = getNumberOf("DEVICES",tgt,timeout);
    if (property != null)
    {
      if (property.length() > 0 && !isStockProperty(property))
      {
        devices_have_query_function = false;
        if ((tpq=getPropertyInformation(context,server,"#0",property,timeout)) != null)
        { // this should always work
          if (tpq[0].prpFormat != TFormat.CF_TEXT)
          { 
            if (TArrayType.isChannel(tpq[0].prpArrayType) || tpq[0].prpSize > n) n = tpq[0].prpSize;
          }
          else
          {
            if (n < 100) n = 100;
          }
          //if (tpq[0].prpFormat == TFormat.CF_TEXT) n = 1;
          prp = property + ".NAM";
        }
        else if (property.contains(".DMASK.") || property.endsWith(".ONLINE"))
        {
          prp = property + ".NAM";
        }
        if (TLinkFactory.isRedirected(context, server, "#0", "PROPS"))
        { // keep the device list from the original target
          prp = null;
        }
      }
    }
    if (prp == null)
    { // fallback :
      devices_have_query_function = false;
      if (n < 0) return null;
      if (n == 0) n++;
      prp = "DEVICES";
    }
    dnqp.target = tgt;
    dnqp.property = prp;
    dnqp.size = n;
    return dnqp;
  }
  /**
   * Returns the number of registered devices for the server and context
   * (and property if non null) given.
   *
   * @param context is the requested context
   * @param server is the requested device server
   * @param property is the desired property (if null or an empty string) the
   * call returns the number of registered devices, else it returns the number
   * of property-specific devices.
   * @param timeout in milliseconds
   * @return the number of devices
   * @throws IOException
   */
  public static int getNumberOfDevices(String context,String server,String property,int timeout) throws IOException
  {
    DeviceNamesQueryParams dnqp = getDeviceNamesQueryProperty(context,server,property,null,timeout);
    return dnqp == null ? 0 : dnqp.size; 
  }
  /**
   * Returns the number of registered devices for the server and context
   * (and property if non null) given.
   *
   * @param context is the requested context
   * @param server is the requested device server
   * @param property is the desired property (if null or an empty string) the
   * call returns the number of registered devices, else it returns the number
   * of property-specific devices.
   * @param filter is a device name filter containing a wildcard character '*'
   * @param timeout in milliseconds
   * @return the number of devices
   * @throws IOException
   */
  public static int getNumberOfDevices(String context,String server,String property,String filter,int timeout) throws IOException
  {
    DeviceNamesQueryParams dnqp = getDeviceNamesQueryProperty(context,server,property,filter,timeout);
    return dnqp == null ? 0 : dnqp.size; 
  }
  private static String[] getDeviceNames64(String context,String server,String property,String filter,int timeout) throws IOException
  {
    DeviceNamesQueryParams dnqp = getDeviceNamesQueryProperty(context,server,property,filter,timeout);
    if (dnqp == null) return null;
   
    TLink tl;
    TDataType dout;
    int cc = 0,i;
    NAME64[] devices;
    String[] strdevs;
    int n = dnqp.size;

    //if (n*64 > maxQueryBufferSize) n = maxQueryBufferSize/64;
    devices = new NAME64[n];
    for (i=0; i<n; i++) devices[i] = new NAME64();
    if (devices.length == 0) return null;
    dout = new TDataType(devices);
    tl = new TLink(dnqp.target,dnqp.property,dout,null,TAccess.CA_READ);
    cc = tl.executeAndClose(timeout);
    if ((cc & TErrorList.CE_SENDDATA) == TErrorList.CE_SENDDATA)
    {
      if ((cc & TErrorList.has_query_function) == TErrorList.has_query_function)
      {
        devices_have_query_function = true;
      }
      cc = 0;
    }
    if (cc != 0)
    {
      if (cc == TErrorList.link_not_open || cc == TErrorList.connection_timeout)
      {
        throw new IOException("/"+context+"/"+server+" timed out getting device names");
      }
      return null;
    }
    // check for empty names (java pre-release 4.0 specialty)
    if (devices[0].name.length() == 0) return null;
//    int ndevs = devices.length;
//    for (n=ndevs; n > 0; n--)
//    { // find the last one in the list with names
//      if (devices[n-1].name.length() > 0) break;
//    }
    for (i=0,n=0; i<devices.length; i++)
    { // recount the returned list
      if (devices[i].name.length() > 0) n++;
    }
    strdevs = new String[n];
    for (i=0; i<n; i++)
    {
      if (devices[i].name.length() == 0) continue;
      strdevs[i] = devices[i].name;
    }
    return strdevs;
  }
 
  /**
   * @deprecated
   * @see getPropertyInformation
   *
   * Returns a list of extended property query information objects associated
   * with the specified context, device server, device. and target property
   * (obtained from the device server).
   *
   * Usually a call to getDeviceProperties() returns a property list
   * A secondary call to getDevicePropertyInformation() returns a list of
   * all property information pertaining to the specified property including
   * all property overloads (maximum 10).  If 'property' is null then the
   * call returns information for the first 10 items.
   * 
   * @param context Is the context of the device server for which the property
   * information is desired.
   * @param server Is the device server for which the property information is
   * desired.
   * @param device Is the device name (module name) for which the property
   * information is desired.
   * @param property Is the property for which the property information is
   * desired.
   *
   * @return An array of PropertyQueryEx (extended Property Query) objects,
   * as obtained from the given device server
   */
  public static PropertyQueryEx[] getDevicePropertyInformation(String context,String server,String device,String property)
  {
    return getDevicePropertyInformation(context,server,device,property,TLink.defaultTimeout);
  }
  /**
   * @deprecated
   * @see getPropertyInformation
   *
   */
  public static synchronized PropertyQueryEx[] getDevicePropertyInformation(String context,String server,String device,String property,int timeout)
  {
    XPropertyQuery[] xpq = getDevicePropertyInformationX(context, server, device, property, timeout);
    if (xpq == null) return null;
    PropertyQueryEx[] pqx = new PropertyQueryEx[xpq.length];
    for (int i=0; i<pqx.length; i++) pqx[i] = new PropertyQueryEx(xpq[i]);
    return pqx;
  }
  public static synchronized int AcquireAndRegisterBitfieldInfo(String context,String server,String tag,short format)
  {
    if (TBitfieldRegistry.getBitfield(context,server,tag) != null) return 0; // already registered
    String tgt;
    if (context == null || context.length() == 0) context = "DEFAULT";
    tgt = new String("/" + context + "/" + server);
    TBitfield bf = new TBitfield(tgt,tag,format);
    return bf.acquireAndRegisterFields(tgt);
  }
  public static synchronized int AcquireAndRegisterStructInfo(String context,String server,String tag)
  {
    //if (TStructRegistry.contains(tag)) return 0; // already registered
    boolean doOnce = TStructRegistry.acquireOnce(tag);
    if (!doOnce && TStructRegistry.contains(tag,context,server)) return 0; // already registered
    int cc = 0, fmt, siz;
    NAME64DBLDBL[] sf = new NAME64DBLDBL[64];
    TDataType din = new TDataType(tag);
    TDataType dout = new TDataType(sf);
    String tgt;
    if (context == null || context.length() == 0) context = "DEFAULT";
    tgt = new String("/"+context+"/"+server+"/#0");
    TLink tl = new TLink(tgt,"STRUCTFORMAT",dout,din,TAccess.CA_READ);
    cc = tl.execute(TLink.defaultTimeout,true);
    if ((cc & TErrorList.CE_SENDDATA) == TErrorList.CE_SENDDATA) cc = 0;
    tl.close();
    if (cc == 0)
    {
      TStructDescription sd = new TStructDescription(tag);
      sd.beginDefinition();
      for (int i=0; i<64; i++)
      {
        fmt = (int)(sf[i].d2val)%512;
        siz = (int)sf[i].d1val;
        if (fmt == TFormat.CF_NULL) break;
        if (fmt == TFormat.CF_STRUCT)
        {
          String stag = sf[i].name.substring(1, sf[i].name.indexOf('>'));
          AcquireAndRegisterStructInfo(context,server,stag);
        }
        if (doOnce) TStructRegistry.fill(tag,sf[i].name,(short)fmt,siz);
        sd.addField(sf[i].name, (short)fmt, siz);
      }
      if (doOnce) TStructRegistry.fill(tag,(short)TFormat.CF_NULL,100);
      sd.setArraySize(100);
      sd.endDefinition();   
      if (doOnce)
      {
        TStructRegistry.acquiredOnce(tag);
        return 0;
      }
      //TStructRegistry.assignServerKey(tag, "/"+context+"/"+server);
      TStructRegistry.assignServerKey(sd,"/"+context+"/"+server);
    }
    else if (cc == TErrorList.illegal_format)
    {
      cc = AcquireAndRegisterStructInfoLegacy(context,server,tag);
    }
    return cc;
  }
  private static int AcquireAndRegisterStructInfoLegacy(String context,String server,String tag)
  {
    if (TStructRegistry.contains(tag)) return 0; // already registered
    int cc = 0;
    INTINT[] sf = new INTINT[64];
    TDataType din = new TDataType(tag);
    TDataType dout = new TDataType(sf);
    String tgt;
    if (context == null || context.length() == 0) context = "DEFAULT";
    tgt = new String("/"+context+"/"+server+"/#0");
    TLink tl = new TLink(tgt,"STRUCTFORMAT",dout,din,TAccess.CA_READ);
    cc = tl.execute(TLink.defaultTimeout,true);
    if ((cc & TErrorList.CE_SENDDATA) == TErrorList.CE_SENDDATA) cc = 0;
    tl.close();
    if (cc == 0)
    {
      TStructDescription sd = new TStructDescription(tag);
      sd.beginDefinition();
      for (int i=0; i<64; i++)
      {
        if ((sf[i].i2val%512) == TFormat.CF_NULL) break;
        //TStructRegistry.fill(tag,(short)sf[i].i2val,sf[i].i1val);
        sd.addField((short)sf[i].i2val,sf[i].i1val);
      }
      //TStructRegistry.fill(tag,(short)TFormat.CF_NULL,100);
      sd.setArraySize(100);
      sd.endDefinition();    
      //TStructRegistry.assignServerKey(tag, "/"+context+"/"+server);
      TStructRegistry.assignServerKey(sd,"/"+context+"/"+server);
    }
    return cc;
  }
  /**
   * @deprecated
   * @see getPropertyInformation
   *
   * Returns a list of extended property query information objects associated
   * with the specified context, device server, device. and target property
   * (obtained from the device server).
   *
   * Usually a call to getDeviceProperties() returns a property list
   * A secondary call to getDevicePropertyInformationX() returns a list of
   * all property information pertaining to the specified property including
   * all property overloads (maximum 10).  If 'property' is null then the
   * call returns information for the first 10 items.  This is an extended
   * method call which returns information as to the array 'type' if the
   * property returns an array, as well as the horizontal axis engineering
   * units and range if the property returns a spectrum and the row size
   * and number or rows if the property returns a double array (matrix).
   * 
   * @param context Is the context of the device server for which the property
   * information is desired.
   * @param server Is the device server for which the property information is
   * desired.
   * @param device Is the device name (module name) for which the property
   * information is desired.
   * @param property Is the property for which the property information is
   * desired.
   *
   * @return An array of XPropertyQuery (extended Property Query) objects,
   * as obtained from the given device server
   *
   */
  public static XPropertyQuery[] getDevicePropertyInformationX(String context,String server,String device,String property)
  {
    return getDevicePropertyInformationX(context,server,device,property,TLink.defaultTimeout);
  }
  /**
   * @deprecated
    * @see getPropertyInformation
  */
  public static XPropertyQuery[] getDevicePropertyInformationX(String context,String server,String device,String property,int timeout)
  {
    return getDevicePropertyInformationX("PROPS", context,server,device,property,timeout);
  }
  private static synchronized XPropertyQuery[] getDevicePropertyInformationX(String stockprop, String context,String server,String device,String property,int timeout)
  {
    TLink tl;
    TDataType dout, din;
    int cc = 0,i;
    String tgt, dev;
    XPropertyQuery[] xpq = null;
    XPropertyQuery xpq1 = new XPropertyQuery();
    byte[] blob = hByteBlobX;
    boolean hasTarget = true;
 
    if (server == null || server.length() == 0) return null;
    if (device == null || device.length() == 0)
      dev = new String("#0");
    else
      dev = device;
    if (context == null || context.length() == 0)
      tgt = new String("/DEFAULT/" + server + "/" + dev);
    else
      tgt = new String("/" + context + "/" + server + "/" + dev);
    int np = nicePropertyQuerySize;
    if (property == null || property.compareTo("*") == 0)
    {
      din = new TDataType();
      String target = "/" + context + "/" + server;
      try
      {
        np = getNumberOf("PROPERTIES", target, timeout);
      }
      catch (IOException e)
      {
        throw new RuntimeException("Could not acquire property information for " + server + " (" + TErrorList.getErrorString(cc) + ")");
      }
      int fudge_factor = np > 150 ? 1 : 2;
      blob = new byte[fudge_factor * np * XPropertyQuery.sizeInBytes]; // allow room for overloads
      hasTarget = false;
    }
    else
    {
      din = new TDataType(property);
    }
    dout = new TDataType(blob,"XPQS");

    while (np > 0)
    {
      try
      {
        tl = new TLink(tgt,stockprop,dout,din,TAccess.CA_READ);
        cc = tl.execute(timeout,true);
        srvAddr = tl.srvAddr;
        if ((cc & TErrorList.CE_SENDDATA) == TErrorList.CE_SENDDATA) cc = 0;
        tl.close();
      }
      catch (Exception e)
      {
        MsgLog.log("getDevicePropertyInformationX", e.getMessage(),TErrorList.non_existent_elem,e,0);
        cc = TErrorList.non_existent_elem;
      }
      if (cc == TErrorList.invalid_transport_size)
      {
        np /= 2;
        blob = new byte[np * XPropertyQuery.sizeInBytes]; // allow room for overloads
        dout = new TDataType(blob,"XPQS");
      }
      else
      {
        break;
      }
    }
    if (cc == 0) // it's at lease a 3.31 server
    {     
      try
      {
        TStructIo.bytesToStruct(xpq1, blob,0,XPropertyQuery.sizeInBytes);
      }
      catch (IOException e1) { e1.printStackTrace(); }

      int nxpq = dout.dCompletionLength;
      if (hasTarget)
      {
        if (xpq1.prpNumOverloads < 1) xpq1.prpNumOverloads = 1; // can't be less than 1 !
        nxpq = xpq1.prpNumOverloads;
        if (nxpq > nicePropertyQuerySize) nxpq = nicePropertyQuerySize;
      }
      if (nxpq == 0) return null;     
     
      if (xpq1.prpNumOverloads < 1) xpq1.prpNumOverloads = 1; // can't be less than 1 !
      if (nxpq > np) nxpq = np;
      xpq = new XPropertyQuery[nxpq];
      xpq[0] = xpq1;
      for (i=1; i<nxpq; i++)
      {
        xpq[i] = new XPropertyQuery();
        try {
          TStructIo.bytesToStruct(xpq[i],blob,i*XPropertyQuery.sizeInBytes,XPropertyQuery.sizeInBytes);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
      return xpq;
    }
    if (cc == TErrorList.link_not_open)
    {
      throw new RuntimeException("Could not acquire property information for " + server + " (" + TErrorList.getErrorString(cc) + ")");
    }
    if (cc == TErrorList.non_existent) return null;
    PropertyQueryLegacy[] pqx = null;
    PropertyQueryLegacy pqx1 = new PropertyQueryLegacy();
    dout = new TDataType(hByteBlobL,"PQSX");
    tl = new TLink(tgt,stockprop,dout,din,TAccess.CA_READ);
    cc = tl.execute(timeout,true);
    tl.close();
    if (cc == 0) // it's at lease a 3.20 server
    {
      byte b[] = pqx1.toByteArray();
      System.arraycopy(hByteBlobL,0,b,0,PropertyQueryLegacy.sizeInBytes);
      pqx1.toStruct();
      int npqx = np;
      if (hasTarget)
      {
        if (pqx1.prpNumOverloads < 1) pqx1.prpNumOverloads = 1; // can't be less than 1 !
        npqx = pqx1.prpNumOverloads;
      }
      if (npqx > nicePropertyQuerySize) npqx = nicePropertyQuerySize;
      pqx = new PropertyQueryLegacy[npqx];
      xpq = new XPropertyQuery[npqx];
      pqx[0] = pqx1;
      for (i=1; i<npqx; i++)
      {
        pqx[i] = new PropertyQueryLegacy();
        b = pqx[i].toByteArray();
        System.arraycopy(hByteBlobL,i*PropertyQueryLegacy.sizeInBytes,b,0,PropertyQueryLegacy.sizeInBytes);
        pqx[i].toStruct();
      }
      for (i=0; i<npqx; i++)
      {
        xpq[i] = new XPropertyQuery();
        xpq[i].prpFormat = pqx[i].prpFormat;
        xpq[i].prpFormatIn = pqx[i].prpFormatIn;
        xpq[i].prpSize = pqx[i].prpSize;
        xpq[i].prpSizeIn = pqx[i].prpSizeIn;
        xpq[i].prpAccess = pqx[i].prpAccess;
        xpq[i].prpDescription = pqx[i].prpDescription;
        xpq[i].prpName = pqx[i].prpName;
        xpq[i].prpNumOverloads = pqx[i].prpNumOverloads;
        xpq[i].prpTag = pqx[i].prpTag;
        xpq[i].prpTagIn = pqx[i].prpTagIn;
        xpq[i].prpRedirection = pqx[i].prpRedirection;
        xpq[i].prpHistoryDepthLong = pqx[i].prpHistoryDepthLong;
        xpq[i].prpHistoryDepthShort = pqx[i].prpHistoryDepthShort;
        xpq[i].prpUnits = pqx[i].prpUnits;
        xpq[i].prpMaxValue = pqx[i].prpMaxValue;
        xpq[i].prpMinValue = pqx[i].prpMinValue;
        xpq[i].prpGraphType = pqx[i].prpGraphType;
      }
      return xpq;
    }
    if (cc == TErrorList.link_not_open)
    {
      throw new RuntimeException("Could not acquire property information for " + server + " (" + TErrorList.getErrorString(cc) + ")");
    }
    // legacy server
    hLegacyByteBlob = null;
    String[] prps = getDeviceProperties(context,server,device);
    if (prps == null || prps.length == 0) return null;
    PropertyQuery[] pq = new PropertyQuery[prps.length];
    xpq = new XPropertyQuery[1];
    byte b[];
    if (hLegacyByteBlob == null) return null;
    for (i=0; i<prps.length; i++)
    {
      pq[i] = new PropertyQuery();
      b = pq[i].toByteArray();
      System.arraycopy(hLegacyByteBlob,i*PropertyQuery.sizeInBytes,b,0,PropertyQuery.sizeInBytes);
      pq[i].toStruct();
      if (pq[i].name.compareTo(property) != 0) continue;
      xpq[0] = new XPropertyQuery();
      xpq[0].prpFormat = pq[i].prpFormat;
      xpq[0].prpSize = pq[i].prpSize;
      xpq[0].prpAccess = pq[i].prpAccess;
      xpq[0].prpDescription = pq[i].prpDesc;
      xpq[0].prpName = pq[i].name;
      xpq[0].prpNumOverloads = 1;
      if ((pq[0].prpAccess & TAccess.CA_WRITE) == TAccess.CA_WRITE)
      {
         xpq[0].prpFormatIn = pq[i].prpFormat;
         xpq[0].prpSizeIn = pq[i].prpSize;
      }
      else    
      {
         xpq[0].prpFormatIn = (byte)TFormat.CF_NULL;
         xpq[0].prpSizeIn = 0;
      }
      USTRING[] egu = new USTRING[1];
      egu[0] = new USTRING();
      dout = new TDataType(egu);
      din = new TDataType();
      String prpegu = new String(property + ".EGU");
      tl = new TLink(tgt,prpegu,dout,din,TAccess.CA_READ);
      cc = tl.execute(timeout,false);
      tl.close();
      if (cc == 0)
      {
        xpq[0].prpMinValue = egu[0].f1val;
        xpq[0].prpMaxValue = egu[0].f2val;
        xpq[0].prpUnits = egu[0].str;
        xpq[0].prpGraphType = (byte)egu[0].ival; 
      }
      break;
    }       
    return xpq;
  }
  /**
   * Returns a list of property query information objects associated
   * with the specified context, device server, device. and target property
   * (obtained from the device server).
   *
   * Usually a call to getDeviceProperties() returns a property list
   * A secondary call to getPropertyInformation() returns a list of
   * all property information pertaining to the specified property including
   * all property overloads (maximum 10).  If 'property' is null then the
   * call returns information for the first 10 items.  This is an extended
   * method call which returns information as to the array 'type' if the
   * property returns an array, as well as the horizontal axis engineering
   * units and range if the property returns a spectrum and the row size
   * and number or rows if the property returns a double array (matrix).
   * 
   * @param context is the context of the device server for which the property
   * information is desired.
   * @param server is the device server for which the property information is
   * desired.
   * @param device is the device name (module name) for which the property
   * information is desired.
   * @param property is the property for which the property information is
   * desired.
   *
   * @return An array of TPropertyQuery objects, as obtained from the given device server
   * A null pointer is returned if the call fails for any reason. 
   *
   */
  public static TPropertyQuery[] getPropertyInformation(String context,String server,String device,String property)
  {
    return getPropertyInformation(context,server,device,property,500);
  }
  /**
   * Returns a list of property query information objects associated
   * with the specified context, device server, device. and target property
   * (obtained from the device server).
   *
   * Usually a call to getDeviceProperties() returns a property list
   * A secondary call to getPropertyInformation() returns a list of
   * all property information pertaining to the specified property including
   * all property overloads (maximum 10).  If 'property' is null then the
   * call returns information for the first 10 items.  This is an extended
   * method call which returns information as to the array 'type' if the
   * property returns an array, as well as the horizontal axis engineering
   * units and range if the property returns a spectrum and the row size
   * and number or rows if the property returns a double array (matrix).
   * 
   * @param context is the context of the device server for which the property
   * information is desired.
   * @param server is the device server for which the property information is
   * desired.
   * @param device is the device name (module name) for which the property
   * information is desired.
   * @param property Is the property for which the property information is
   * desired.
   * @param timeout is the time in milliseconds to wait for the call to complete
   *
   * @return An array of TPropertyQuery objects, as obtained from the given device server.
   * A null pointer is returned if the call fails for any reason. 
   */
  public static TPropertyQuery[] getPropertyInformation(String context,String server,String device,String property,int timeout)
  {
    try
    {
      return getPropertyInformation("PROPS",context,server,device,property,timeout);
    }
    catch (IOException e)
    {
      return null;
    }
  }
  public static int pingServer(String context,String server,int timeout)
  {
    return pingServer(context,server,timeout,false);
  }
  public static int pingServer(String context,String server,int timeout,boolean output)
  {
    if (context == null || server == null)
    {
      if (output) System.out.println("error: parameter list error");
      return TErrorList.argument_list_error;
    }
    String target = "/"+context+"/"+server;
    char[] st = new char[32];
    TDataType dout = new TDataType(st);
    int cc = TErrorList.address_unknown;
    try
    {
      TLink tl = new TLink(target,"SRVSTARTTIME",dout,null,TAccess.CA_READ);
      cc = tl.execute(timeout,true);
      tl.close();
      if (output && cc == 0) System.out.println("running since "+new String(st));
    }
    catch (Exception e)
    {
      // just swallow it ...
    }
    if (output && cc != 0) System.out.println("error: "+TErrorList.getErrorString(cc));
    return cc;
  }
  public static boolean isValidServer(String context,String server)
  {
    srvAddr = new TSrvEntry(server,context);
    if (srvAddr.eqmName == null) return false;
    return true;
  }
  /**
   * Returns the number of registered properties for the give server and context
   *
   * @param context is the requested context
   * @param server is the requested device server
   * @param timeout in milliseconds
   * @return the number of properties
   * @throws IOException
   */
  public static int getNumberOfProperties(String context,String server,int timeout) throws IOException
  {
    if (context == null || server == null) return 0;
    return getNumberOf("PROPERTIES", "/"+context+"/"+server, timeout);
  }
  private static synchronized TPropertyQuery[] getPropertyInformation(String stockprop,String context,String server,String device,String property,int timeout) throws IOException
  {
    TLink tl = null;
    TDataType dout, din;
    int cc = 0, i;
    String tgt, dev;
    TPropertyQuery[] tpq = null;
    TPropertyQuery tpq0 = new TPropertyQuery();
    boolean hasTarget = true;
    byte[] blob = hByteBlob;

    if (server == null || server.length() == 0)
    {
      MsgLog.log("getPropertyInformation", "argument list error",TErrorList.argument_list_error,null,0);
      return null;
    }
    if (device == null || device.length() == 0)
      dev = new String("#0");
    else
      dev = device;
    if (context == null || context.length() == 0)
      tgt = new String("/DEFAULT/" + server + "/" + dev);
    else
      tgt = new String("/" + context + "/" + server + "/" + dev);
    if (property == null || property.compareTo("*") == 0)
    {
      hasTarget = false;
      din = new TDataType();
      //String target = "/" + context + "/" + server;
      int np = nicePropertyQuerySize;
      try
      {
        np = getNumberOf("PROPERTIES", tgt, timeout);
      }
      catch (Exception e)
      {
        MsgLog.log("getPropertyInformation",e.toString(),TErrorList.connection_timeout,e,0);
        throw new IOException("Could not acquire property information for " + server + " (" + e.toString() + ")");
      }
      blob = new byte[2 * np * TPropertyQuery.sizeInBytes]; // allow room for overloads
    }
    else
    {
      if (TQuery.isStockProperty(property))
      {
        stockprop = "STOCKPROPS";
      }
      din = new TDataType(property);
    }
    dout = new TDataType(blob,"PRPQSr4");
    try
    {
      tl = new TLink(tgt,stockprop,dout,din,TAccess.CA_READ);
      cc = tl.execute(timeout,true);
      srvAddr = tl.srvAddr;
      if ((cc & TErrorList.CE_SENDDATA) == TErrorList.CE_SENDDATA) cc = 0;
      tl.close();
    }
    catch (Exception e)
    {
      MsgLog.log("getPropertyInformation", e.toString(),cc,e,0);
      cc = TErrorList.address_unknown;
      if (tl != null) tl.close();
    }
    if (cc == 0) // it's at lease a 4.0 server
    {     
      try
      {
        TStructIo.bytesToStruct(tpq0, blob,0,TPropertyQuery.sizeInBytes);
      }
      catch (IOException e1)
      {
        e1.printStackTrace();
        cc = TErrorList.code_failure;
        MsgLog.log("getPropertyInformation", e1.toString(),cc,e1,0);
      }
      int ntpq = dout.dCompletionLength;
      if (hasTarget)
      {
        if (tpq0.prpNumOverloads < 1) tpq0.prpNumOverloads = 1; // can't be less than 1 !
        ntpq = tpq0.prpNumOverloads;
        if (ntpq > nicePropertyQuerySize) ntpq = nicePropertyQuerySize;
      }
      if (ntpq == 0) return null;
      tpq = new TPropertyQuery[ntpq];
      tpq[0] = tpq0;
      for (i=1; i<ntpq; i++)
      {
        tpq[i] = new TPropertyQuery();
        try
        {
          TStructIo.bytesToStruct(tpq[i],blob,i*TPropertyQuery.sizeInBytes,TPropertyQuery.sizeInBytes);
        }
        catch (Exception e)
        {
          cc = TErrorList.code_failure;
          MsgLog.log("getPropertyInformation", e.toString(),cc,e,0);         
        }
      }
      return tpq;
    }
    if (cc == TErrorList.link_not_open)
    {
      MsgLog.log("getPropertyInformation", TErrorList.getErrorString(cc),cc,null,0);         
      throw new IOException("Could not acquire property information for " + server + " (" + TErrorList.getErrorString(cc) + ")");
    }
    if (cc == TErrorList.non_existent ||
        cc == TErrorList.non_existent_property) return null;
    // try the old way :
    XPropertyQuery[] xpq = getDevicePropertyInformationX(stockprop,context,server,device,property,timeout);
    if (xpq == null || xpq.length == 0) return null;
    tpq = new TPropertyQuery[xpq.length];
    for (i=0; i<xpq.length; i++)
    {
      tpq[i] = new TPropertyQuery();
      tpq[i].prpFormat = xpq[i].prpFormat;
      tpq[i].prpFormatIn = xpq[i].prpFormatIn;
      tpq[i].prpSize = xpq[i].prpSize;
      tpq[i].prpSizeIn = xpq[i].prpSizeIn;
      tpq[i].prpAccess = xpq[i].prpAccess;
      tpq[i].prpDescription = xpq[i].prpDescription;
      tpq[i].prpName = xpq[i].prpName;
      tpq[i].prpNumOverloads = xpq[i].prpNumOverloads;
      tpq[i].prpTag = xpq[i].prpTag;
      tpq[i].prpTagIn = xpq[i].prpTagIn;
      tpq[i].prpRedirection = xpq[i].prpRedirection;
      tpq[i].prpHistoryDepthLong = xpq[i].prpHistoryDepthLong;
      tpq[i].prpHistoryDepthShort = xpq[i].prpHistoryDepthShort;
      tpq[i].prpUnits = xpq[i].prpUnits;
      tpq[i].prpMaxValue = xpq[i].prpMaxValue;
      tpq[i].prpMinValue = xpq[i].prpMinValue;
      tpq[i].prpGraphType = xpq[i].prpGraphType;
      tpq[i].numRows = xpq[i].numRows;
      tpq[i].rowSize = xpq[i].rowSize;
      tpq[i].rngMaxValue = xpq[i].rngMaxValue;
      tpq[i].rngMinValue = xpq[i].rngMinValue;
      tpq[i].rngUnits = xpq[i].rngUnits;
    }
    return tpq;
  }
  /**
   * Returns a list of extended property query information objects associated
   * with the specified context, device server, device. and target property
   * (obtained from the device server).  Typically, the device name is ignored
   * in this query.
   *
   * Usually a call to getStockProperties() returns a property list
   * A secondary call to getStockPropertyInformationX() returns a list of
   * all property information pertaining to the specified property including
   * all property overloads (maximum 10).  If 'property' is null then the
   * call returns information for the first 10 items.  This is an extended
   * method call which returns information as to the array 'type' if the
   * property returns an array, as well as the horizontal axis engineering
   * units and range if the property returns a spectrum and the row size
   * and number or rows if the property returns a double array (matrix).
   * 
   * @param context Is the context of the device server for which the property
   * information is desired.
   * @param server Is the device server for which the property information is
   * desired.
   * @param device Is the device name (module name) for which the property
   * information is desired.
   * @param property Is the property for which the property information is
   * desired.
   *
   * @return An array of XPropertyQuery (extended Property Query) objects,
   * as obtained from the given device server
   * A null pointer is returned if the call fails for any reason. 
   */
  public static TPropertyQuery[] getStockPropertyInformation(String context,String server,String device,String property)
  {
    return getStockPropertyInformation(context,server,device,property,500);
  }
  /**
   * Returns a list of extended property query information objects associated
   * with the specified context, device server, device. and target property
   * (obtained from the device server).  Typically, the device name is ignored
   * in this query.
   *
   * Usually a call to getStockProperties() returns a property list
   * A secondary call to getStockPropertyInformationX() returns a list of
   * all property information pertaining to the specified property including
   * all property overloads (maximum 10).  If 'property' is null then the
   * call returns information for the first 10 items.  This is an extended
   * method call which returns information as to the array 'type' if the
   * property returns an array, as well as the horizontal axis engineering
   * units and range if the property returns a spectrum and the row size
   * and number or rows if the property returns a double array (matrix).
   * 
   * @param context is the context of the device server for which the property
   * information is desired.
   * @param server is the device server for which the property information is
   * desired.
   * @param device is the device name (module name) for which the property
   * information is desired.
   * @param property is the property for which the property information is
   * desired.
   * @param timeout is the amount of time in milliseconds to wait for the call to
   * complete
   *
   * @return An array of XPropertyQuery (extended Property Query) objects,
   * as obtained from the given device server
   * A null pointer is returned if the call fails for any reason. 
   */
  public static TPropertyQuery[] getStockPropertyInformation(String context,String server,String device,String property,int timeout)
  {
    try
    {
      return getPropertyInformation("STOCKPROPS",context,server,device,property,timeout);
    }
    catch (IOException e)
    {
      return null;
    }
  }
  /**
   * @deprecated
   * @see getStockPropertyInformation
   */
  public static synchronized XPropertyQuery[] getStockPropertyInformationX(String context,String server,String device,String property)
  {
    return getDevicePropertyInformationX("STOCKPROPS", context,server,device,property,TLink.defaultTimeout);
  }
  private static ServerQuery[] getXTagList(String context,String tagtype,String subsys,String importance,int timeout)
  {
    int cc,n,i;
    TDataType dout;
    TDataType din;
    TLink tl;
    StringBuffer host = new StringBuffer(32);
    StringBuffer query = new StringBuffer(32);
    short[] numout = new short[1];
    TDataType numoutData = new TDataType(numout);
    NAME16[] inplist = new NAME16[2];
    USTRING[] taglist;
    ServerQuery[] strlist;
    boolean isFecRequest = tagtype.compareToIgnoreCase("FECS") == 0;

    if (subsys == null || subsys.length() == 0)
    {
      inplist[0] = new NAME16("ALL");
    }
    else
    {
      inplist[0] = new NAME16(subsys);
    }
    if (importance == null || importance.length() == 0)
    {
      inplist[1] = new NAME16("ALL");   
    }
    else
    {
      inplist[1] = new NAME16(importance);
    }
    din = new TDataType(inplist);
   
    host.delete(0,31); query.delete(0,31);
    if (context != null && context.length() != 0)
    {
      host.insert(0,"ENS/" + context);
    }
    else
    {
      host.insert(0,"ENS");
    }
    query.insert(0,"N" + tagtype);
    try
    {
      tl = new TLink(host.toString(),query.toString(),numoutData,din,TAccess.CA_READ);
      cc = tl.execute(timeout,true);
      srvAddr = tl.srvAddr;
      tl.close();
    }
    catch (Exception e)
    {
      MsgLog.log("getXTagList", e.getMessage(),TErrorList.non_existent_elem,e,0);
      cc = TErrorList.non_existent_elem;
    }
    if (cc != 0) return null;
    if (numout[0] == 0 && subsys != null && subsys.length() > 0) numout[0] = 100;
    // Get Tags from name server (synchronous call)
    query.delete(0,31);
    query.insert(0,tagtype);
    n = numout[0];
    taglist = new USTRING[n];
    for (i=0; i<n; i++) taglist[i] = new USTRING();
    if (taglist.length == 0) return null;
    if (numout[0] > taglist.length) numout[0] = (short)taglist.length; 
    dout = new TDataType(taglist);
    tl = new TLink(host.toString(),query.toString(),dout,din,TAccess.CA_READ);
    cc = tl.execute(TLink.defaultTimeout,true);
    tl.close();
    if (cc != 0) return null;
    strlist = new ServerQuery[n];
    int zidx, cntr=0;
    String srv;
    for (i=0; i<n; i++)
    {
      String s = taglist[i].getString();
      if (s.length() < 64) continue;
      strlist[i] = new ServerQuery();
      srv = s.substring(0,16).trim();
      if (!isFecRequest && srv.endsWith("&"))
      {
        srv = srv.substring(0, 15) + s.substring(48,64).trim();
      }
      strlist[i].setName(srv);
      strlist[i].setOs(s.substring(16,24).trim());
      strlist[i].setSubsystem(s.substring(24,32).trim());
      zidx = s.indexOf(0, 32);
      strlist[i].setXref(s.substring(32,zidx).trim());
      if (isFecRequest)
      {
        strlist[i].setContext(s.substring(zidx+1).trim());
      }
      else
      {
        strlist[i].setContext(context);
      }
      strlist[i].setImportance(taglist[i].tm);
      strlist[i].setAddress(taglist[i].ival);
      strlist[i].setXRefIsFec(!isFecRequest);
      cntr++;
    }
    if (cntr < n) strlist = Arrays.copyOf(strlist, cntr);
    return strlist;
  }
  private static int tryAccessLock(String context, String server, AccessLockType lockType)
  {
    short[] lvals = new short[2];
    lvals[0] = (short)lockType.ordinal();
    lvals[1] = (short)1;
    TDataType din = new TDataType(lvals);
    TLink lnk = new TLink("/"+context+"/"+server,"ACCESSLOCK",null,din,TAccess.CA_WRITE|TAccess.CA_RETRY);
    int rc = lnk.execute(TLink.defaultTimeout,true);
    lnk.close();
    return rc;
  }
  /**
   * Establishes an access lock on the device server specified
   *
   * @param context is the context containing the device server
   * @param server is the targeted device server
   * @param lockType is the lock type requested 
   * @param lockDuration is the duration of the access lock (in seconds)
   * @return 0 upon success or a TINE error code.
   *
   * @include eg_SetAccessLock.java
   */
  public static int setAccessLock(String context, String server, AccessLockType lockType, int lockDuration)
  {
    int rc = tryAccessLock(context, server, lockType);
    if (rc != 0) return rc;
    return TLinkFactory.setAccessLock(context, server, lockType, lockDuration);
  }
  /**
   * Retrieves the access lock information on the device server specified
   *
   * @param context is the context containing the device server
   * @param server is the targeted device server
   * @return a string array containing the user and address of the owner of
   * the current access lock.  If there is no access lock, the strings are empty.
   *
   * @include eg_GetAccessLock.java
   */
  public static String[] getAccessLockInformation(String context, String server)
  {
    NAME32[] n32 = new NAME32[3];
    TDataType dout = new TDataType(n32);
    TLink lnk = new TLink("/"+context+"/"+server,"ACCESSLOCK",dout,null,TAccess.CA_READ);
    int rc = lnk.execute(TLink.defaultTimeout);
    lnk.close();
    if (rc != 0) return null;
    String[] rs = new String[3];
    rs[0] = n32[0].getName();
    rs[1] = n32[1].getName();
    rs[2] = n32[2].getName();
    return rs;
  }
  /**
   * Removes an access lock on the server specified.
   *
   * @param context is the targeted context of the server
   * @param server is the targeted device server
   * @return a tine return code
   */
  public static void removeAccessLock(String context, String server)
  {
    TLinkFactory.removeAccessLock(context, server);
  }
  public static synchronized int getThresholds(String context,String server, String property,float[] tmax,float[] tmin)
  {
    if (tmax == null || tmin == null) return TErrorList.invalid_parameter;
    if (tmax.length == 0 || tmin.length == 0) return TErrorList.dimension_error;
    TDataType dt = new TDataType(tmax);
    TLink tl = new TLink("/"+context+"/"+server+"/#0",property+".TMAX",dt,null,TAccess.CA_READ);
    int cc = tl.execute();
    tl.close();
    int dlen = dt.getCompletionLength();
    boolean pifDone = false;
    TPropertyQuery[] tpq = null;
    switch (cc)
    {
      default:
        return cc;
      case TErrorList.link_blacklisted:
      case TErrorList.illegal_property:
        tpq = getPropertyInformation(context,server,"#0",property);
        if (tpq == null) return TErrorList.io_error;
        tmax[0] = tpq[0].prpMaxValue;
        tmin[0] = tpq[0].prpMinValue;
        cc = 0; dlen = 1;
        pifDone = true;
      case TErrorList.success:
        break;
    }
    if (dlen == 1)
    { // one threshold applies to all elements
      for (int i=1; i<tmax.length; i++)
      { // so fill them in ...
        tmax[i] = tmax[0];
      }
    }
    dt = new TDataType(tmin);
    tl = new TLink("/"+context+"/"+server+"/#0",property+".TMIN",dt,null,TAccess.CA_READ);
    cc = tl.execute();
    tl.close();
    dlen = dt.getCompletionLength();
    switch (cc)
    {
      default:
      case TErrorList.illegal_property:
        if (!pifDone)
        { // had success with TMAX but not here!
          tpq = getPropertyInformation(context,server,"#0",property);
          if (tpq == null) return TErrorList.io_error;
          tmin[0] = tpq[0].prpMinValue;
        }
        cc = 0; dlen = 1;
      case TErrorList.success:
        break;
    }
    if (dlen == 1)
    { // one threshold applies to all elements
      for (int i=1; i<tmin.length; i++)
      { // so fill them in ...
        tmin[i] = tmin[0];
      }
    }
    for (int i=0; i<tmax.length && i<tmin.length; i++)
    {
      if (tmin[i] >= tmax[i])
      { // doesn't make sense
        if (!pifDone)
        { // had success with TMAX but not here!
          tpq = getPropertyInformation(context,server,"#0",property);
          if (tpq == null) return TErrorList.io_error;
        }       
        if (tmax[i] < tpq[0].prpMinValue) tmax[i] = tpq[0].prpMaxValue;
        tmin[i] = tpq[0].prpMinValue;
      }
    }
    return 0;
  }
  class stRowHndlr implements RowHandler
  { // the Row Handler will be called when all columns have been read in
    String prp;
    public void setProperty(String p) { prp = p; }
    String dev;
    public void setDevice(String d) { dev = d; }
    int sizOut;
    public void setSizeOut(int siz) { sizOut = siz; }
    int fmtOut;
    public void setFormatOut(int fmt) { fmtOut = fmt; }
    int sizIn;
    public void setSizeIn(int siz) { sizIn = siz; }
    int fmtIn;
    public void setFormatIn(int fmt) { fmtIn = fmt; }
    int acc;
    public void setAccess(int access) { acc = access; }
    int mod;
    public void setMode(int mode) { mod = mode; }
    float tolAbs;
    float tolRel;
    String tolStr;
    public void setToleranceString(String tol) { tolStr = tol; }
    String tagOut;
    public void setTagOut(String tag) { tagOut = tag; }
    String tagIn;
    public void setTagIn(String tag) { tagIn = tag; }
    int tmr;
    public void setTimer(int timer) { tmr = timer; }
    String req;
    public void setRequiredState(String reqState) { req = reqState; }
    int msk;
    public void setMask(int mask) { msk = mask; }
    String tgt;
    public void setTgt(String target) { tgt = target; }
    String inpt;
    public void setInput(String input) { inpt = input; }
    LinkedList<SelfTestItem> lst = new LinkedList<SelfTestItem>();
    stRowHndlr()
    {
    }
    public int process(int index)
    {
      SelfTestItem sti = new SelfTestItem(dev,prp,new TDataType(sizOut,(short)fmtOut),new TDataType(sizIn,(short)fmtIn),acc,0,0,req);
      sti.setTgt(tgt);
      sti.setMask(msk);
      sti.setInpt(inpt);
      lst.add(sti);
      return 0;
    }
  } 
  class prpHndlr implements csvHandler
  {
    private stRowHndlr rHndlr;
    prpHndlr(stRowHndlr rowHndlr)
    {
      rHndlr = rowHndlr;
    }
    public int process(String strValue,int index)
    {
      if (strValue == null || strValue.length() == 0) return 0;
      rHndlr.setProperty(strValue);
      return 0;
    }
  }
  class devHndlr implements csvHandler
  {
    private stRowHndlr rHndlr;
    devHndlr(stRowHndlr rowHndlr)
    {
      rHndlr = rowHndlr;
    }
    public int process(String strValue,int index)
    {
      if (strValue == null || strValue.length() == 0) return 0;
      rHndlr.setDevice(strValue);
      return 0;
    }
  }
  class sizOutHndlr implements csvHandler
  {
    private stRowHndlr rHndlr;
    sizOutHndlr(stRowHndlr rowHndlr)
    {
      rHndlr = rowHndlr;
    }
    public int process(String strValue,int index)
    {
      if (strValue == null || strValue.length() == 0) return 0;
      int siz = 0;
      try { siz = Integer.parseInt(strValue); } catch (Exception e) {};
      rHndlr.setSizeOut(siz);
      return 0;
    }
  }
  class sizInHndlr implements csvHandler
  {
    private stRowHndlr rHndlr;
    sizInHndlr(stRowHndlr rowHndlr)
    {
      rHndlr = rowHndlr;
    }
    public int process(String strValue,int index)
    {
      if (strValue == null || strValue.length() == 0) return 0;
      int siz = 0;
      try { siz = Integer.parseInt(strValue); } catch (Exception e) {};
      rHndlr.setSizeIn(siz);
      return 0;
    }
  }
  class fmtOutHndlr implements csvHandler
  {
    private stRowHndlr rHndlr;
    fmtOutHndlr(stRowHndlr rowHndlr)
    {
      rHndlr = rowHndlr;
    }
    public int process(String strValue,int index)
    {
      if (strValue == null || strValue.length() == 0) return 0;
      int fmt = TFormat.getFormatCode(strValue);
      rHndlr.setFormatOut(fmt);
      return 0;
    }
  }
  class fmtInHndlr implements csvHandler
  {
    private stRowHndlr rHndlr;
    fmtInHndlr(stRowHndlr rowHndlr)
    {
      rHndlr = rowHndlr;
    }
    public int process(String strValue,int index)
    {
      if (strValue == null || strValue.length() == 0) return 0;
      int fmt = TFormat.getFormatCode(strValue);
      rHndlr.setFormatIn(fmt);
      return 0;
    }
  }
  class datTgtHndlr implements csvHandler
  {
    private stRowHndlr rHndlr;
    datTgtHndlr(stRowHndlr rowHndlr)
    {
      rHndlr = rowHndlr;
    }
    public int process(String strValue,int index)
    {
      if (strValue == null || strValue.length() == 0) return 0;
      rHndlr.setTgt(strValue);
      return 0;
    }
  }
  class datMskHndlr implements csvHandler
  {
    private stRowHndlr rHndlr;
    datMskHndlr(stRowHndlr rowHndlr)
    {
      rHndlr = rowHndlr;
    }
    public int process(String strValue,int index)
    {
      if (strValue == null || strValue.length() == 0) return 0;
      int msk = 0;
      try { msk = Integer.parseInt(strValue); } catch (Exception e) {};
      rHndlr.setMask(msk);
      return 0;
    }
  }
  class datInHndlr implements csvHandler
  {
    private stRowHndlr rHndlr;
    datInHndlr(stRowHndlr rowHndlr)
    {
      rHndlr = rowHndlr;
    }
    public int process(String strValue,int index)
    {
      if (strValue == null || strValue.length() == 0) return 0;
      rHndlr.setInput(strValue);
      return 0;
    }
  }
  class tmrHndlr implements csvHandler
  {
    private stRowHndlr rHndlr;
    tmrHndlr(stRowHndlr rowHndlr)
    {
      rHndlr = rowHndlr;
    }
    public int process(String strValue,int index)
    {
      if (strValue == null || strValue.length() == 0) return 0;
      float tmr = 0;
      try { tmr = Float.parseFloat(strValue); } catch (Exception e) {};
      int itmr = (int)(tmr * 1000);
      rHndlr.setTimer(itmr);
      return 0;
    }
  }
  class accHndlr implements csvHandler
  {
    private stRowHndlr rHndlr;
    accHndlr(stRowHndlr rowHndlr)
    {
      rHndlr = rowHndlr;
    }
    public int process(String strValue,int index)
    {
      if (strValue == null || strValue.length() == 0) return 0;
     
      int acc = TAccess.CA_READ;
      int mod = TMode.CM_SINGLE;
      if (strValue.compareToIgnoreCase("WRITE") == 0) acc = TAccess.CA_WRITE;
      rHndlr.setAccess(acc);
      if (strValue.compareToIgnoreCase("MONITOR") == 0) mod = TMode.CM_TIMER;
      if (strValue.compareToIgnoreCase("TIMER") == 0) mod = TMode.CM_TIMER;
      rHndlr.setMode(mod);
      return 0;
    }
  }
  class tolHndlr implements csvHandler
  {
    private stRowHndlr rHndlr;
    tolHndlr(stRowHndlr rowHndlr)
    {
      rHndlr = rowHndlr;
    }
    public int process(String strValue,int index)
    {
      if (strValue == null || strValue.length() == 0) return 0;
      rHndlr.setToleranceString(strValue);
      return 0;
    }
  }
  class reqHndlr implements csvHandler
  {
    private stRowHndlr rHndlr;
    reqHndlr(stRowHndlr rowHndlr)
    {
      rHndlr = rowHndlr;
    }
    public int process(String strValue,int index)
    {
      if (strValue == null || strValue.length() == 0) return 0;
      rHndlr.setRequiredState(strValue);
      return 0;
    }
  }
  public static SelfTestItem[] getServerSelfTest(String context, String server)
  {
    char[] stChars = new char[32000];
    TDataType dout = new TDataType(stChars);
    TLink lnk = new TLink("/"+context+"/"+server,"SRVSELFTEST",dout,null,TAccess.CA_READ);
    int rc = lnk.executeAndClose(TLink.defaultTimeout);
    if (rc != 0) return null;
    int p = dout.getCompletionLength();
    String stString = new String(stChars,0,p);
   
    csvColumn[] stCols = new csvColumn[26];
    stRowHndlr stRows = new TQuery().new stRowHndlr();
    stCols[0] = new csvColumn("PROPERTY","",new TQuery().new prpHndlr(stRows));
    stCols[1] = new csvColumn("DEVICE","",new TQuery().new devHndlr(stRows));
    stCols[2] = new csvColumn("SIZE_OUT","",new TQuery().new sizOutHndlr(stRows));
    stCols[3] = new csvColumn("FORMAT_OUT","",new TQuery().new fmtOutHndlr(stRows));
    stCols[4] = new csvColumn("SIZE_IN","",new TQuery().new sizInHndlr(stRows));
    stCols[5] = new csvColumn("FORMAT_IN","",new TQuery().new fmtInHndlr(stRows));
    stCols[6] = new csvColumn("DATA_TGT","",new TQuery().new datTgtHndlr(stRows));
    stCols[7] = new csvColumn("DATA_MASK","",new TQuery().new datMskHndlr(stRows));
    stCols[8] = new csvColumn("DATA_IN","",new TQuery().new datInHndlr(stRows));
    stCols[9] = new csvColumn("WAIT","",new TQuery().new tmrHndlr(stRows));
    stCols[10] = new csvColumn("ACCESS","",new TQuery().new accHndlr(stRows));
    stCols[11] = new csvColumn("TOLERANCE","",new TQuery().new tolHndlr(stRows));
    stCols[12] = new csvColumn("REQUIRED","",new TQuery().new reqHndlr(stRows));
    // open it   
    csv expFile = new csv(stString.toCharArray());
    // read it
    rc = expFile.readFile(stCols,stRows);
    // close it
    if (rc != TErrorList.no_such_file)
      TFecLog.log("get registered exports and properties from exports.csv : " + TErrorList.errorString[rc]);
   
    return stRows.lst.toArray(new SelfTestItem[0]);
    //return stString;
  }
}

TOP

Related Classes of de.desy.tine.queryUtils.TQuery

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.