package de.desy.tine.addrUtils;
import java.io.IOException;
import java.util.Arrays;
import de.desy.tine.client.TLink;
import de.desy.tine.dataUtils.TDataType;
import de.desy.tine.definitions.TAccess;
import de.desy.tine.definitions.TErrorList;
import de.desy.tine.exceptions.TineRuntimeErrorException;
import de.desy.tine.queryUtils.TQuery;
import de.desy.tine.types.*;
/**
* Utility routines for accessing information from the
* Equipment Name Server (ENS).
*
* @author duval
*
*/
public class ENSTools
{
/**
* Signals the ENS to ping all registered servers in the context
* given and remove from the database those which do not respond.
*
* @param context is the context for which the flush activity should take place
*
* @return 0 upon success or a TINE return code
*/
public static int flushNonRespondingServers(String context)
{
if (context == null || context.length() == 0) return TErrorList.invalid_parameter;
String dn = "/SITE/ENS/"+context;
TLink lnk = new TLink(dn,"REMOVENOTRUNNING",null,null,TAccess.CA_WRITE);
int cc = lnk.execute(500, true);
lnk.close();
return cc;
}
/**
* Sets the allowed server down time at the ENS
*
* This applies to ALL servers in the ENS database and establishes
* a maximum duration a server is allowed to be down before being removed
* from the database
*
* @param downTime is the allowed down time in seconds
*
* @return 0 upon success or a TINE return code
*/
public static int setAllowedDownTime(int downTime)
{
if (downTime < 3600) return TErrorList.out_of_range;
String dn = "/SITE/ENS";
int[] dt = new int[1];
dt[0] = downTime;
TDataType din = new TDataType(dt);
TLink lnk = new TLink(dn,"ALLOWEDDEADTIME",null,din,TAccess.CA_WRITE);
int cc = lnk.execute(500, true);
lnk.close();
return cc;
}
/**
* Gets the allowed server down time from the ENS
*
* This applies to ALL servers in the ENS database and constitutes
* a maximum duration a server is allowed to be down before being removed
* from the database
*
* @return the allowed down time in seconds if successful or a negative
* TINE return code upon error
*/
public static int getAllowedDownTime()
{
String dn = "/SITE/ENS";
int[] dt = new int[1];
TDataType dout = new TDataType(dt);
TLink lnk = new TLink(dn,"ALLOWEDDEADTIME",dout,null,TAccess.CA_READ);
int cc = lnk.executeAndClose(500);
return cc == 0 ? dt[0] : -cc;
}
/**
* Provides a list of the available allowed subsystems at the ENS and an
* associated list of subsystem descriptions (depending on input).
*
* @param subsystems input/output supplies a reference to a string array which
* is to hold the list of allowed subsystems upon successful completion. If
* this array is not dimensioned large enough to contain the available list, the
* list will be truncated.
* @param descriptions input/output supplies a reference to a string array which is
* to hold the list of subsystem descriptions upon successful completion. If a
* null is passed, then no descriptions are returned.
*
* @return the total number of available subsystems (independent of the dimensions of
* the input subsystems array.
* @throws IOException, TineRuntimeErrorException
*/
public static int getAllowedDeviceSubsystems(String[] subsystems,String[] descriptions) throws IOException
{
if (subsystems == null || subsystems.length == 0) throw new TineRuntimeErrorException(TErrorList.argument_list_error);
USTRING[] ustr = new USTRING[200];
TDataType dout = new TDataType(ustr);
TLink tl = new TLink("/SITE/ENS/DEFAULT","SUBSYSTEMS.DESCRIPTIONS",dout,null,TAccess.CA_READ);
int cc = tl.executeAndClose(1000);
if (cc == TErrorList.link_timeout || cc == TErrorList.connection_timeout)
throw new IOException("timed out while contacting the ENS");
if (cc != 0) throw new TineRuntimeErrorException(cc);
int n = dout.getCompletionLength();
int m = subsystems.length;
if (descriptions != null && descriptions.length < m) m = descriptions.length;
if (m > n) m = n;
String[] sp;
for (int i=0; i<m; i++)
{
sp = ustr[i].str.split(":");
subsystems[i] = sp[0].trim();
if (descriptions != null) descriptions[i] = sp[1].trim();
}
return n;
}
public static String[] getServerAliasList(String contextAndServer)
{
String[] parts = contextAndServer.split("/");
int i0 = 0;
if (parts.length < 2) return null;
if (parts[0].length() == 0)
{ // given with leading '/'
i0 = 1;
if (parts.length < 3) return null;
}
return getServerAliasList(parts[i0],parts[i0+1]);
}
public static String[] getServerAliasList(String context, String server)
{
if (context == null || server == null) return null;
String dn = "/SITE/ENS";
NAME32[] dt = new NAME32[2];
dt[0] = new NAME32(context);
dt[1] = new NAME32(server);
TDataType din = new TDataType(dt);
NAME64[] lst = new NAME64[32]; // 32 = a nice query size
TDataType dout = new TDataType(lst);
TLink lnk = new TLink(dn,"EXPORTALIASLIST",dout,din,TAccess.CA_READ);
if (lnk.executeAndClose(500) != 0) return null;
int n = dout.getCompletionLength();
String[] slst = new String[n];
for (int i=0; i<n; i++) { slst[i] = lst[i].getName(); }
return slst;
}
public static String[] getFecAliasList(String fec)
{
if (fec == null) return null;
String dn = "/SITE/ENS/"+fec;
NAME16[] lst = new NAME16[32]; // 32 = a nice query size
TDataType dout = new TDataType(lst);
TLink lnk = new TLink(dn,"FECALIASLIST",dout,null,TAccess.CA_READ);
if (lnk.executeAndClose(500) != 0) return null;
int n = dout.getCompletionLength();
String[] slst = new String[n];
for (int i=0; i<n; i++) { slst[i] = lst[i].getName(); }
return slst;
}
static boolean legacyEns = TSrvEntry.isLegacyEns();
public static int sendExportInformationToENS(FECAddr fec,FECInfo info, SrvAddr da)
{
if (fec == null || info == null || da == null) return TErrorList.argument_list_error;
if (TSrvEntry.currentConfiguredNameServerTag == null)
{
TQuery.getModuleAddressInfo("ENS","DEFAULT");
}
fec.setPortOffset(fec.portOffset);
// prepare it and send it out: devAddr-- + FecAddr + FecInfo ...
int siz = legacyEns ? SrvAddr.legacySizeInBytes : SrvAddr.sizeInBytes;
byte[] expAddr = new byte[siz + FECInfo.getSizeInBytes()];
System.arraycopy(da.toByteArray(legacyEns), 0, expAddr, 0, siz);
System.arraycopy(info.toByteArray(), 0, expAddr, siz, FECInfo.getSizeInBytes());
TDataType din = new TDataType(expAddr, "");
TDataType dout = new TDataType();
if (TSrvEntry.currentConfiguredNameServerTag != null)
{ // this should always point to the primary ENS
TLink lnk = new TLink(TSrvEntry.currentConfiguredNameServerTag,"EXPORT",dout,din,TAccess.CA_WRITE);
int cc = lnk.executeAndClose(500);
if (cc == TErrorList.illegal_data_size && !legacyEns)
{ // set this for the next call
TSrvEntry.setLegacyEns(true);
}
return cc;
}
else
{
return TErrorList.not_running;
}
}
/**
* Sends the information to the ENS as if a booting FEC is
* issuing a plug-and-play registration
*
* This routine can be used by an ENS administrator to register aliases, etc.
*
* @param da the the full server address information
* @param info is the accompanying FEC information
*
* @return 0 upon success or a TINE error code
*/
public static int sendExportInformationToENS(SrvAddr da, FECInfo info)
{
if (info == null || da == null) return TErrorList.argument_list_error;
if (TSrvEntry.currentConfiguredNameServerTag == null)
{
TQuery.getModuleAddressInfo("ENS","DEFAULT");
}
// prepare it and send it out : devAddr-- + FecAddr + FecInfo ...
int siz = legacyEns ? SrvAddr.legacySizeInBytes : SrvAddr.sizeInBytes;
byte[] expAddr = new byte[siz + FECInfo.getSizeInBytes()];
System.arraycopy(da.toByteArray(legacyEns), 0, expAddr, 0, siz);
System.arraycopy(info.toByteArray(), 0, expAddr, siz, FECInfo.getSizeInBytes());
TDataType din = new TDataType(expAddr, "");
TDataType dout = new TDataType();
// this should always point to the primary ENS
if (TSrvEntry.currentConfiguredNameServerTag != null)
{
TLink lnk = new TLink(TSrvEntry.currentConfiguredNameServerTag,"EXPORT",dout,din,TAccess.CA_WRITE);
int cc = lnk.executeAndClose(500);
if (cc == TErrorList.illegal_data_size && !legacyEns)
{ // set this for the next call
TSrvEntry.setLegacyEns(true);
}
return cc;
}
else
{
return TErrorList.not_running;
}
}
/**
* Removes the given FEC from the ENS database
*
* @param fecName is the FEC name to be removed from the ENS database
*
* @return 0 upon success or a TINE error code
*/
public static int removeFECFromENS(String fecName)
{
if (fecName == null) return TErrorList.argument_list_error;
if (TSrvEntry.currentConfiguredNameServerTag == null)
{
TQuery.getModuleAddressInfo("ENS","DEFAULT");
}
NAME16[] fn = new NAME16[1];
fn[0] = new NAME16(fecName);
TDataType din = new TDataType(fn);
if (TSrvEntry.currentConfiguredNameServerTag != null)
{
String dn = TSrvEntry.currentConfiguredNameServerTag + "/FEC";
TLink rmvLnk = new TLink(dn,"REMOVE",null,din,TAccess.CA_WRITE);
int cc = rmvLnk.execute(500, true);
rmvLnk.close();
return cc;
}
else
{
return TErrorList.not_running;
}
}
/**
* Obtains a unique FEC name applicable to the context and server names given.
*
* @param context the context of the new server
* @param server the server name of the new server
*
* @return a NAME16I object whose name field contains the suggested FEC name for the
* input parameters and whose integer field contains the status of the FEC name. Namely
* if the context and server already exist, then the assigned FEC name is returned along
* with the status 'TErrorList.name_already_exists'.
*
* @throws TineRuntimeErrorException (likely invalid_parameter or connection_timeout)
*/
public static NAME16I getSuggestedFECName(String context,String server)
{
NAME32[] n32 = new NAME32[1];
if (server == null) throw new TineRuntimeErrorException(TErrorList.invalid_parameter);
if (context == null) context = "DEFAULT";
TLink tl = new TLink("/SITE/ENS/"+context,"SuggestFecName",new TDataType(n32),new TDataType(server),TAccess.CA_READ);
int cc = tl.executeAndClose();
if (cc != 0 && !TErrorList.hasData(cc)) throw new TineRuntimeErrorException(cc);
return new NAME16I(n32[0].name,TErrorList.getErrorCode(cc));
}
/**
* Removes the given device server from the ENS database
*
* @param context is the context of the device server to be removed
* @param deviceServer is the device server to be removed
*
* @return 0 upon success or a TINE error code
*/
public static int removeDeviceServerFromENS(String context, String deviceServer)
{
if (context == null || deviceServer == null) return TErrorList.argument_list_error;
if (TSrvEntry.currentConfiguredNameServerTag == null)
{
TQuery.getModuleAddressInfo("ENS","DEFAULT");
}
NAME32[] sn = new NAME32[1];
sn[0] = new NAME32(deviceServer);
TDataType din = new TDataType(sn);
if (TSrvEntry.currentConfiguredNameServerTag != null)
{
String dn = TSrvEntry.currentConfiguredNameServerTag + "/" + context;
TLink rmvLnk = new TLink(dn,"REMOVE",null,din,TAccess.CA_WRITE);
int cc = rmvLnk.execute(500, true);
rmvLnk.close();
return cc;
}
else
{
return TErrorList.not_running;
}
}
/**
* Retrieves the registered device server groups from the Group ENS
*
* @param context is the context whose groups are desired
*
* @return a list of registered device groups
*/
public static String[] getGroupsFromGENS(String context)
{
if (context == null || context.length() == 0) return null;
if (TSrvEntry.currentConfiguredNameServerTag == null)
{
TQuery.getModuleAddressInfo("GENS","SITE");
}
NAME64[] sn = new NAME64[512];
TDataType dout = new TDataType(sn);
if (TSrvEntry.currentConfiguredNameServerTag != null)
{
TLink grpsLnk = new TLink("/SITE/GENS","GROUPS",dout,null,TAccess.CA_READ);
int cc = grpsLnk.execute(500, true);
grpsLnk.close();
int len = dout.getCompletionLength();
if (cc == 0 && len > 0)
{
String[] parts;
String[] st = new String[len];
int n = 0;
for (int i=0; i<len; i++)
{
parts = sn[i].getName().split("/");
if (parts.length > 2)
{
if (parts[1].compareToIgnoreCase(context) == 0)
{
st[n++] = parts[2];
}
}
}
String[] s = new String[n];
for (int i=0; i<n; i++) s[i] = st[i];
return s;
}
}
return null;
}
/**
* Retrieves the registered device server groups from the Group ENS
*
* @param context is the context of the device group
* @param group is the device group
*
* @return a list of the registered group members for the given device group
*/
public static String[] getGroupMembersFromGENS(String context, String group)
{
if (context == null || context.length() == 0) return null;
if (group == null || group.length() == 0) return null;
if (TSrvEntry.currentConfiguredNameServerTag == null)
{
TQuery.getModuleAddressInfo("GENS","SITE");
}
NAME32[] cn = new NAME32[1];
cn[0] = new NAME32(context);
NAME64[] sn = new NAME64[512];
TDataType dout = new TDataType(sn);
TDataType din = new TDataType(cn);
if (TSrvEntry.currentConfiguredNameServerTag != null)
{
TLink grpsLnk = new TLink("/SITE/GENS/"+group,"MEMBERS",dout,din,TAccess.CA_READ);
int cc = grpsLnk.execute(500, true);
grpsLnk.close();
int len = dout.getCompletionLength();
if (cc == 0 && len > 0)
{
String[] st = new String[len];
for (int i=0; i<len; i++)
{
st[i] = sn[i].getName();
}
return st;
}
}
return null;
}
public static GrpMbr[] getGroupMemberInformationFromGENS(String context, String group)
{
if (context == null || context.length() == 0) return null;
if (group == null || group.length() == 0) return null;
if (TSrvEntry.currentConfiguredNameServerTag == null)
{
TQuery.getModuleAddressInfo("GENS","SITE");
}
GrpMbr[] gm = new GrpMbr[100];
for (int i=0; i<100; i++) gm[i] = new GrpMbr();
TDataType dout = new TDataType(gm);
if (TSrvEntry.currentConfiguredNameServerTag != null)
{
TLink grpsLnk = new TLink("/SITE/GENS/"+context+"/"+group,"MEMBERS",dout,null,TAccess.CA_READ);
int cc = grpsLnk.executeAndClose(500);
int len = dout.getCompletionLength();
if (cc == 0 && len > 0)
{
return Arrays.copyOf(gm, len);
}
}
return null;
}
/**
* Removes the given device server from the specified device group
*
* @param context is the context of the device group
* @param deviceServer is the device server group member to be removed
* @param group is the device group
*
* @return 0 upon success or a TINE error code
*/
public static int removeDeviceServerFromGroup(String context, String deviceServer, String group)
{
if (context == null || deviceServer == null || group == null) return TErrorList.argument_list_error;
if (context.length() == 0 || deviceServer.length() == 0 || group.length() == 0) return TErrorList.argument_list_error;
if (TSrvEntry.currentConfiguredNameServerTag == null)
{
TQuery.getModuleAddressInfo("GENS","SITE");
}
NAME32[] sn = new NAME32[3];
sn[0] = new NAME32(deviceServer);
sn[1] = new NAME32(group);
sn[2] = new NAME32(context);
TDataType din = new TDataType(sn);
if (TSrvEntry.currentConfiguredNameServerTag != null)
{
TLink rmvLnk = new TLink("/SITE/GENS","SEPARATE",null,din,TAccess.CA_WRITE);
int cc = rmvLnk.execute(500, true);
rmvLnk.close();
return cc;
}
else
{
return TErrorList.not_running;
}
}
/**
* Adds a device server group member to the group specified
*
* This routine can be used by an ENS administrator to add device servers to a given
* group as if a booting server had itself issued a plug-and-play request.
*
* @param context is the context of the device group
* @param deviceServer is the device server to add to the group
* @param group is the device group
* @param subSystem is the subsystem to which the group should belong (relevant if
* the given device group is new).
* @param groupIndex is a 'metric' which is used by the group server to establish
* the device order presented by the group server (smaller group indices come first).
*
* @return 0 upon success or a TINE error code
*/
public static int addDeviceServerToGroup(String context, String deviceServer, String group, String subSystem, int groupIndex)
{
return addDeviceServerToGroup(context,deviceServer,group,subSystem,groupIndex,null,null);
}
/**
* Adds a device server group member to the group specified
*
* This routine can be used by an ENS administrator to add device servers to a given
* group as if a booting server had itself issued a plug-and-play request.
*
* @param context is the context of the device group
* @param deviceServer is the device server to add to the group
* @param group is the device group
* @param subSystem is the subsystem to which the group should belong (relevant if
* the given device group is new).
* @param groupIndex is a 'metric' which is used by the group server to establish
* the device order presented by the group server (smaller group indices come first).
* @param groupDevicePrefix is a prefix identifier to be applied to the device list
* associated with the deviceServer given. Pass a 'null' or empty entry if no prefix
* is desired.
* @param groupDevicePostfix is a postfix identifier to be applied to the device list
* associated with the deviceServer given. Pass a 'null' or empty entry if no postfix
* is desired.
*
* @return 0 upon success or a TINE error code
*/
public static int addDeviceServerToGroup(String context, String deviceServer, String group, String subSystem, int groupIndex,String groupDevicePrefix,String groupDevicePostfix)
{
if (context == null || deviceServer == null || group == null) return TErrorList.argument_list_error;
if (context.length() == 0 || deviceServer.length() == 0 || group.length() == 0) return TErrorList.argument_list_error;
if (TSrvEntry.currentConfiguredNameServerTag == null)
{
TQuery.getModuleAddressInfo("GENS","SITE");
}
int len = 7;
NAME32[] sn = new NAME32[7];
sn[0] = new NAME32(deviceServer);
sn[1] = new NAME32(group);
sn[2] = new NAME32(context);
sn[3] = new NAME32(Integer.toString(groupIndex));
if (subSystem == null || subSystem.length() == 0)
{
subSystem = "DIAG";
}
sn[4] = new NAME32(subSystem);
if (groupDevicePrefix == null) groupDevicePrefix = "";
sn[5] = new NAME32(groupDevicePrefix);
if (groupDevicePostfix == null) groupDevicePostfix = "";
sn[6] = new NAME32(groupDevicePostfix);
TDataType din = new TDataType(sn,len);
if (TSrvEntry.currentConfiguredNameServerTag != null)
{
TLink addLnk = new TLink("/SITE/GENS","JOIN",null,din,TAccess.CA_WRITE);
int cc = addLnk.execute(500, true);
addLnk.close();
return cc;
}
else
{
return TErrorList.not_running;
}
}
/**
* Switch to the 'next configured' Equipment Name Server.
*/
public static void toggleENS()
{
TSrvEntry.toggleENS();
}
/**
* Gets the current configured ENS IP address as a string.
* @return the current configured ENS address
*/
public static String getCurrentENSAddress()
{
String addr;
try
{
if (TSrvEntry.currentConfiguredNameServerTag == null)
{
TQuery.getModuleAddressInfo("ENS","DEFAULT");
}
addr = new TSrvEntry("ENS","SITE").fecAddr.fecHost.getHostAddress();
}
catch (Exception e)
{
addr = "not available";
}
return addr;
}
/**
* Gets the current configured ENS server name
* @return the current configured ENS server name
*/
public static String getCurrentENS()
{
if (TSrvEntry.currentConfiguredNameServerTag == null)
{
TQuery.getModuleAddressInfo("ENS","DEFAULT");
}
String ens = TSrvEntry.currentConfiguredNameServerTag == null ?
"unknown" : new String(TSrvEntry.currentConfiguredNameServerTag);
return ens;
}
}