//: TLink.java
package de.desy.tine.headers;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.DataOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.Arrays;
import de.desy.tine.addrUtils.TSrvEntry;
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.definitions.TFormat;
import de.desy.tine.definitions.TStrings;
import de.desy.tine.endianUtils.Swap;
import de.desy.tine.server.logger.MsgLog;
import de.desy.tine.types.SPECTRUM;
public final class TContract
{
public String eqmProperty; // 64 char
public String eqmDeviceName; // 64 char
public String eqmName; // 8 char
public int dataSizeIn;
public int dataSizeOut;
public byte hEqmName; // as yet un-used
public byte dataAccess;
public byte dataFormatIn;
public byte dataFormatOut;
public String dataTagIn; // 16 char
public String dataTagOut; // 16 char
// non 'network' fields :
public byte[] extStringSpace;
public int extStringSize = 0;
public static final short CTR_RENEWAL = 60;
public static final short CTR_MAXIMUM = 32767;
static public final int hdrSizeInBytes =
TStrings.PROPERTY_NAME_SIZE +
TStrings.DEVICE_NAME_SIZE +
TStrings.EQM_NAME_SIZE +
2 * 4 + // 2 ints (size in and size out)
4 + // 4 bytes
2 * TStrings.TAG_NAME_SIZE;
int totalSizeInBytes;
public ByteArrayOutputStream dBuffer;
private boolean isLegacy = false;
public boolean equals(TContract contract)
{
if (contract.eqmProperty.compareToIgnoreCase(eqmProperty) != 0) return false;
if (contract.eqmDeviceName.compareToIgnoreCase(eqmDeviceName) != 0) return false;
if (contract.eqmName.compareTo(eqmName) != 0) return false;
if (contract.dataSizeIn != dataSizeIn) return false;
if (contract.dataSizeOut != dataSizeOut) return false;
if (TAccess.toBase(contract.dataAccess) != TAccess.toBase(dataAccess)) return false;
if (contract.dataFormatIn != dataFormatIn) return false;
if (contract.dataFormatOut != dataFormatOut) return false;
if (contract.dataTagIn.compareTo(dataTagIn) != 0) return false;
if (contract.dataTagOut.compareTo(dataTagOut) != 0) return false;
if (contract.extStringSize != extStringSize) return false;
if (contract.extStringSize > 0)
{
if (!Arrays.equals(contract.extStringSpace,extStringSpace)) return false;
}
return true;
}
// construct a modern contract from a legacy contract
public TContract(TContractP5 legacyContract)
{
eqmProperty = legacyContract.eqmProperty;
eqmDeviceName = legacyContract.eqmDeviceName;
eqmName = legacyContract.eqmName;
dataSizeIn = legacyContract.dataSizeIn;
dataSizeOut = legacyContract.dataSizeOut;
hEqmName = legacyContract.hEqmName;
dataAccess = legacyContract.dataAccess;
dataFormatIn = legacyContract.dataFormatIn;
dataFormatOut = legacyContract.dataFormatOut;
dataTagIn = legacyContract.dataTagIn;
dataTagOut = legacyContract.dataTagOut;
extStringSize = 0;
extStringSpace = null;
dBuffer = legacyContract.dBuffer; // keep the reference ?
}
// local constructor for local histories, alarm watches, etc....
public TContract(String property,String device,String eqm,TDataType dout,TDataType din,short access)
{
eqmProperty = property;
eqmDeviceName = device;
eqmName = eqm;
if (din != null)
{
dataSizeIn = din.dArrayLength;
dataFormatIn = (byte)din.dFormat;
dataTagIn = din.getTag();
}
else
{
dataSizeIn = 0;
dataFormatIn = (byte)TFormat.CF_NULL;
dataTagIn = "";
}
if (dout != null)
{
dataSizeOut = dout.dArrayLength;
dataFormatOut = (byte)dout.dFormat;
dataTagOut = dout.getTag();
}
else
{
dataSizeOut = 0;
dataFormatOut = (byte)TFormat.CF_NULL;
dataTagOut = "";
}
dataAccess = (byte)access;
}
//going out (client-side constructor)
public TContract(TLink lnk)
{
int i, padding = 0;
// get 6-character module name
TSrvEntry srv;
srv = new TSrvEntry(lnk);
if (srv.fecAddr == null) return;
isLegacy = srv.isLegacy;
if (lnk.srvAddr != null)
{ // this part is always valid
lnk.srvAddr.fecAddr = srv.fecAddr;
lnk.srvAddr.eqmName = srv.eqmName;
// fill in the local fields ...
eqmName = srv.eqmName;
eqmProperty = lnk.devProperty;
eqmDeviceName = lnk.devName;
dataSizeOut = lnk.dOutput.getArrayLength();
dataSizeIn = lnk.dInput.getArrayLength();
dataFormatOut = (byte)lnk.dOutput.getFormat();
dataFormatIn = (byte)lnk.dInput.getFormat();
dataAccess = (byte)lnk.devAccess;
dataTagOut = lnk.dOutput.getTag();
dataTagIn = lnk.dInput.getTag();
}
try
{
if (!isLegacy)
{
int dslen = lnk.devName == null ? 0 : lnk.devName.length();
if (dslen > TStrings.DEVICE_NAME_SIZE)
{ // a long device name (requires extended string space)
extStringSize = dslen - TStrings.DEVICE_NAME_SIZE + 1;
padding = extStringSize % 2;
}
dBuffer = new ByteArrayOutputStream(hdrSizeInBytes);
DataOutputStream ds = new DataOutputStream(dBuffer);
byte[] bstr = new byte[TStrings.PROPERTY_NAME_SIZE];
byte[] tmp = lnk.devProperty.getBytes();
for (i=0; i<TStrings.PROPERTY_NAME_SIZE; i++) bstr[i] = i < tmp.length ? tmp[i] : 0;
ds.write(bstr,0,TStrings.PROPERTY_NAME_SIZE);
tmp = lnk.devName.getBytes();
if (tmp.length > TStrings.DEVICE_NAME_SIZE)
{ // a long device name (requires extended string space)
for (i=0; i<TStrings.DEVICE_NAME_SIZE-1; i++) bstr[i] = tmp[i];
byte[] amp = "&".getBytes(); // insert continuation character
bstr[TStrings.DEVICE_NAME_SIZE-1] = amp[0];
extStringSpace = new byte[extStringSize+padding];
int charsRemaining = tmp.length - TStrings.DEVICE_NAME_SIZE + 1;
if (charsRemaining > TStrings.DEVICE_NAME_MAXSIZE)
charsRemaining = TStrings.DEVICE_NAME_MAXSIZE;
for (i=0; i<charsRemaining; i++)
extStringSpace[i] = tmp[TStrings.DEVICE_NAME_SIZE-1+i];
if (padding > 0) extStringSpace[extStringSize] = 0;
}
else
{
for (i=0; i<TStrings.DEVICE_NAME_SIZE; i++) bstr[i] = i < tmp.length ? tmp[i] : 0;
}
ds.write(bstr,0,TStrings.DEVICE_NAME_SIZE);
tmp = srv.eqmName.getBytes();
for (i=0; i<TStrings.EQM_NAME_SIZE; i++) bstr[i] = i < tmp.length ? tmp[i] : 0;
ds.write(bstr,0,TStrings.EQM_NAME_SIZE);
int inlen = lnk.dInput.getArrayLength();
int outlen = lnk.dOutput.getArrayLength();
if (lnk.dOutput.getFormat() == TFormat.CF_STRUCT ||
TFormat.isAdjustableLength(lnk.dOutput.getFormat()))
{
outlen = lnk.dOutput.getSizeInBytes();
}
else if (lnk.dOutput.getFormat()== TFormat.CF_HISTORY)
{
outlen *= TFormat.getCarriedFormatSize(lnk.dOutput.getTag()) + TFormat.getHistoryHeaderSize();
}
if (lnk.dInput.getFormat() == TFormat.CF_STRUCT ||
TFormat.isAdjustableLength(lnk.dInput.getFormat()))
{
inlen = lnk.dInput.getSizeInBytes();
}
else if (lnk.dInput.getFormat()== TFormat.CF_HISTORY)
{
inlen *= TFormat.getCarriedFormatSize(lnk.dInput.getTag()) + TFormat.getHistoryHeaderSize();
}
ds.writeInt(Swap.Long(inlen));
ds.writeInt(Swap.Long(outlen));
ds.writeByte(0);
ds.writeByte(lnk.devAccess);
ds.writeByte((byte)lnk.dInput.getFormat());
ds.writeByte((byte)lnk.dOutput.getFormat());
tmp = lnk.dInput.getTag().getBytes();
for (i=0; i<TStrings.TAG_NAME_SIZE; i++) bstr[i] = i < tmp.length ? tmp[i] : 0;
ds.write(bstr,0,TStrings.TAG_NAME_SIZE);
tmp = lnk.dOutput.getTag().getBytes();
for (i=0; i<TStrings.TAG_NAME_SIZE; i++) bstr[i] = i < tmp.length ? tmp[i] : 0;
ds.write(bstr,0,TStrings.TAG_NAME_SIZE);
if (extStringSize > 0) ds.write(extStringSpace);
totalSizeInBytes = hdrSizeInBytes + extStringSize + padding + lnk.dInput.getSizeInBytes();
ds.close();
}
else
{
setLegacy(lnk);
}
}
catch (IOException e)
{
e.printStackTrace();
MsgLog.log("TContract",e.toString(),TErrorList.code_failure,e,0);
}
}
public void setLegacy(TLink lnk)
{
if (lnk == null) return;
int i;
try
{
isLegacy = true;
dBuffer = new ByteArrayOutputStream(TContractP5.hdrSizeInBytes);
DataOutputStream ds = new DataOutputStream(dBuffer);
byte[] bstr = new byte[TStrings.PROPERTY_NAME_SHORTSIZE];
byte[] tmp = lnk.devProperty.getBytes();
byte[] tm2 = lnk.devName.getBytes();
if (tm2.length > TStrings.DEVICE_NAME_SHORTSIZE && tmp.length < TStrings.DEVICE_NAME_SHORTSIZE)
{ // the Release 3.31 Channel Access Long device names trick ...
for (i=0; i<TStrings.DEVICE_NAME_SHORTSIZE; i++)
bstr[i] = (i < tmp.length) ? tmp[i] : 0; bstr[TStrings.DEVICE_NAME_SHORTSIZE] = 0;
for (i=0; i<TStrings.DEVICE_NAME_SHORTSIZE-1; i++)
bstr[i+TStrings.DEVICE_NAME_SHORTSIZE+1] =
(i < tm2.length - TStrings.DEVICE_NAME_SHORTSIZE + 1) ? tm2[i+TStrings.DEVICE_NAME_SHORTSIZE-1] : 0;
byte[] amp = "&".getBytes();
tm2[15] = amp[0];
}
else
{ // normal (legacy) case
for (i=0; i<TStrings.PROPERTY_NAME_SHORTSIZE; i++) bstr[i] = i < tmp.length ? tmp[i] : 0;
}
ds.write(bstr,0,TStrings.PROPERTY_NAME_SHORTSIZE);
for (i=0; i<TStrings.DEVICE_NAME_SHORTSIZE; i++) bstr[i] = i < tm2.length ? tm2[i] : 0;
ds.write(bstr,0,TStrings.DEVICE_NAME_SHORTSIZE);
tmp = lnk.srvAddr.eqmName.getBytes();
for (i=0; i<TStrings.EQM_NAME_SIZE; i++) bstr[i] = i < tmp.length ? tmp[i] : 0;
ds.write(bstr,0,TStrings.EQM_NAME_SIZE);
int inlen = lnk.dInput.getArrayLength();
int outlen = lnk.dOutput.getArrayLength();
if (lnk.dOutput.getFormat() == TFormat.CF_STRUCT) outlen = lnk.dOutput.getSizeInBytes();
if (lnk.dInput.getFormat() == TFormat.CF_STRUCT) inlen = lnk.dInput.getSizeInBytes();
ds.writeInt(Swap.Long(inlen));
ds.writeInt(Swap.Long(outlen));
ds.writeByte(0);
ds.writeByte(lnk.devAccess);
ds.writeByte((byte)lnk.dInput.getFormat());
ds.writeByte((byte)lnk.dOutput.getFormat());
tmp = lnk.dInput.getTag().getBytes();
for (i=0; i<TStrings.TAG_NAME_SHORTSIZE; i++) bstr[i] = i < tmp.length ? tmp[i] : 0;
ds.write(bstr,0,TStrings.TAG_NAME_SHORTSIZE);
tmp = lnk.dOutput.getTag().getBytes();
for (i=0; i<TStrings.TAG_NAME_SHORTSIZE; i++) bstr[i] = i < tmp.length ? tmp[i] : 0;
ds.write(bstr,0,TStrings.TAG_NAME_SHORTSIZE);
totalSizeInBytes = TContractP5.hdrSizeInBytes + lnk.dInput.getSizeInBytes();
ds.close();
}
catch (IOException e)
{
e.printStackTrace();
MsgLog.log("TContract.setLegacy",e.getMessage(),TErrorList.code_failure,e,0);
}
}
private void prepareInComing(DataInputStream ds)
{
byte[] d = new byte[1024];
try
{
ds.read(d,0,TStrings.PROPERTY_NAME_SIZE);
eqmProperty = new String(d,0,TStrings.PROPERTY_NAME_SIZE).trim();
ds.read(d,0,TStrings.DEVICE_NAME_SIZE);
eqmDeviceName = new String(d,0,TStrings.DEVICE_NAME_SIZE).trim();
ds.read(d,0,TStrings.EQM_NAME_SIZE);
eqmName = new String(d,0,TStrings.EQM_NAME_SIZE).trim();
dataSizeIn = Swap.Long(ds.readInt());
dataSizeOut = Swap.Long(ds.readInt());
hEqmName = ds.readByte();
dataAccess = ds.readByte();
dataFormatIn = ds.readByte();
dataFormatOut = ds.readByte();
ds.read(d,0,TStrings.TAG_NAME_SIZE);
dataTagIn = new String(d,0,TStrings.TAG_NAME_SIZE).trim();
ds.read(d,0,TStrings.TAG_NAME_SIZE);
dataTagOut = new String(d,0,TStrings.TAG_NAME_SIZE).trim();
}
catch (IOException e)
{
e.printStackTrace();
MsgLog.log("TContract.prepareInComing",e.toString(),TErrorList.code_failure,e,0);
}
}
public TContract(byte[] data, int off, int len)
{
try
{
ByteArrayInputStream is = new ByteArrayInputStream(data,off,len);
DataInputStream ds = new DataInputStream(is);
prepareInComing(ds);
ds.close();
is.close();
}
catch (IOException e)
{
e.printStackTrace();
MsgLog.log("TContract",e.toString(),TErrorList.code_failure,e,0);
}
}
public void setExtendedStringSpace(byte[] extBytes,int extOffset, int extLength)
{
try
{
extStringSize = extLength;
extStringSpace = new byte[extLength];
System.arraycopy(extBytes, extOffset, extStringSpace, 0, extLength);
}
catch (Exception e)
{
e.printStackTrace();
MsgLog.log("setExtendedStringSpace", e.toString(),TErrorList.code_failure,e,0);
extStringSize = 0;
extStringSpace = null;
}
return;
}
public String getExtendedDeviceName()
{
String dev = eqmDeviceName;
if (extStringSize > 0 && dev.length() > TStrings.DEVICE_NAME_SIZE-1)
{
dev = dev.substring(0, TStrings.DEVICE_NAME_SIZE-1) + new String(extStringSpace);
}
return dev;
}
public TContract(DataInputStream ds) // coming in (server constructor)
{
prepareInComing(ds);
}
public TContract(ByteArrayInputStream inBuffer) // coming in (server constructor)
{
DataInputStream ds = new DataInputStream(inBuffer);
prepareInComing(ds);
try
{
ds.close();
}
catch (IOException e)
{
e.printStackTrace();
MsgLog.log("TContract",e.toString(),TErrorList.code_failure,e,0);
}
}
public int getOutputDataSize()
{
int fmtsiz = 0;
if ((fmtsiz=TFormat.formatSizeOf(dataFormatOut)) > 0)
{
int datasize = fmtsiz * dataSizeOut;
datasize += TFormat.getFormatHeaderSize(dataFormatOut);
if (dataFormatOut == TFormat.CF_SPECTRUM) datasize += SPECTRUM.hdrSizeInBytes;
return datasize;
}
return 0;
}
private String nameTag = null;
public String getNameTag()
{
if (nameTag == null)
nameTag = new String("<"+eqmName+">/"+eqmDeviceName+"["+eqmProperty+"]");
return nameTag;
}
public String toString()
{
String msg = new String("target : <"+eqmName+">/"+eqmDeviceName+"["+eqmProperty+"]");
msg = msg.concat("" + TAccess.toString(dataAccess) + " access");
msg = msg.concat("\ninput : " + dataSizeIn + " " + TFormat.toString(dataFormatIn) + " value(s)");
if (dataTagIn.length() > 0) msg = msg.concat(" tag = " + dataTagIn);
msg = msg.concat("\noutput : " + dataSizeOut + " " + TFormat.toString(dataFormatOut) + " value(s)");
if (dataTagOut.length() > 0) msg = msg.concat(" tag = " + dataTagOut);
return msg;
}
public byte[] toByteArray()
{
return dBuffer != null ? dBuffer.toByteArray() : null;
}
}