/*******************************************************************************
* Copyright (c) 2011 The Board of Trustees of the Leland Stanford Junior University
* as Operator of the SLAC National Accelerator Laboratory.
* Copyright (c) 2011 Brookhaven National Laboratory.
* EPICS archiver appliance is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*******************************************************************************/
package org.epics.archiverappliance.config;
import gov.aps.jca.dbr.DBR;
import gov.aps.jca.dbr.DBR_CTRL_Double;
import gov.aps.jca.dbr.DBR_CTRL_Int;
import gov.aps.jca.dbr.DBR_LABELS_Enum;
import gov.aps.jca.dbr.GR;
import gov.aps.jca.dbr.PRECISION;
import java.util.HashMap;
import org.apache.log4j.Logger;
import org.epics.archiverappliance.data.DBRTimeEvent;
import org.epics.pvdata.pv.PVStructure;
/** this class is used for getting the meta data
* <p>
* @author luofeng li
*/
public class MetaInfo {
private static Logger logger = Logger.getLogger(MetaInfo.class.getName());
private static Logger configLogger = Logger.getLogger("config." + MetaInfo.class.getName());
/**
* the name of ioc where this pv is
*/
private String hostName;
/**
* lowerAlarmLimit is responding to the LOLO field of ioc
*/
private double lowerAlarmLimit;
/**
* the lower control limit
*/
private double loweCtrlLimit;
/**
* lowerDisplayLimit is responding to the LOPR field of ioc
*/
private double lowerDisplayLimit;
/**
* lowerWarningLimit is responding to the LOW field of ioc
*/
private double lowerWarningLimit;
/**
* upperAlarmLimit is responding to the HIHI field of ioc
*/
private double upperAlarmLimit;
/**
* the upper control limit
*/
private double upperCtrlLimit;
/**
* upperDisplayLimit is responding to the HOPR field of ioc
*/
private double upperDisplayLimit;
/**
* upperWarningLimit is responding to the HIGH field of ioc
*/
private double upperWarningLimit;
/**
* the precision of the pv
*/
private int precision;
/**
* the unit of the pv
*/
private String unit ;
/**
* The events count of the pv in one minute
*/
private long eventCount;
/**
* the alias name of pv, this is corresponding to the NAME field IOC
*/
private String aliasName="";
/**
* the type of the pv
*/
private ArchDBRTypes archDBRTypes;
/**
* the event rate and the unit is events per second
*/
private double eventRate ;
/**
* the total storage size of pv data in one minute and the unit is bytes.
*/
private long storageSize;
/**
* the storage rate of pv data and the unit is bytes per second
*/
private double storageRate;
/**
* the element count of the pv's value.
*/
private int count;
/**
* the pv is vector or not. when count > 1 ,isVector=true. otherelse isVector=false;
*/
private boolean isVector=false;
/**
* if the pv is a label (dbr.isLABELS()),the label of the pv is stored in label[].
*/
private String label[];
/**
* time from the first data received(monitor change function called) to the last data received
*/
private double second=0;
/**
* the start time of monitorchange first called and startTime=System.currentTimeMillis();
*/
private long startTime=0L;
/**
* store other information include MDEL,ADEL
*/
private HashMap<String,String> otherMetaInfo=new HashMap<String,String>();
/**
* add other meta info such as MDEL,ADEL
* @param name the info name
* @param value the info value
*/
public void addOtherMetaInfo(String name,Double value) {
if(value == null) {
logger.warn("Skipping adding meta info for " + name);
return;
}
otherMetaInfo.put(name, value.toString());
}
/**
*
* @return the host name where this pv is
*/
public String getHostName() {
return hostName;
}
/**
*
* @param hostName the host name where this pv is
*/
public void setHostName(String hostName) {
this.hostName = hostName;
}
/**
* add other meta info such as MDEL,ADEL
* @param name the info name
* @param value the info value
*/
public void addOtherMetaInfo(String name,String value) {
if(value == null) {
logger.warn("Skipping adding meta info for " + name);
return;
}
otherMetaInfo.put(name, value.toString());
}
/**
* set the starting time of archiving this pv
* @param startTime the number of milliseconds since 1970/01/01
*/
public void setStartTime(long startTime) {
this.startTime=startTime;
}
/**
*
* @return the HashMap including all other info for this pv.
*/
public HashMap<String,String> getOtherMetaInfo() {
return otherMetaInfo;
}
/**
* save the basical info from dbr
* @param pvName the name of the PV
* @param dbr EPICS DB record
* @param configService ConfigService
*/
public void applyBasicInfo(String pvName, final DBR dbr, ConfigService configService) {
if (dbr.isLABELS()) {
logger.debug("Updating labels for ENUM pv " + pvName);
final DBR_LABELS_Enum labels = (DBR_LABELS_Enum)dbr;
label=labels.getLabels();
} else if (dbr instanceof DBR_CTRL_Double) {
logger.debug("Updating metafields for DBR_CTRL_Double for pv " + pvName);
final DBR_CTRL_Double ctrl = (DBR_CTRL_Double)dbr;
this.lowerDisplayLimit= ctrl.getLowerDispLimit().doubleValue();
this.upperDisplayLimit=ctrl.getUpperDispLimit().doubleValue();
this.lowerWarningLimit=ctrl.getLowerWarningLimit().doubleValue();
this.upperWarningLimit=ctrl.getUpperWarningLimit().doubleValue();
this.lowerAlarmLimit=ctrl.getLowerAlarmLimit().doubleValue();
this.loweCtrlLimit=ctrl.getLowerCtrlLimit().doubleValue();
this.upperCtrlLimit=ctrl.getUpperCtrlLimit().doubleValue();
this.upperAlarmLimit=ctrl.getUpperAlarmLimit().doubleValue();
this.precision=ctrl.getPrecision();
this.unit=ctrl.getUnits();
updateTypeInfo(pvName, configService);
} else if (dbr instanceof DBR_CTRL_Int) {
logger.debug("Updating metafields for DBR_CTRL_Int pv " + pvName);
final DBR_CTRL_Int ctrl = (DBR_CTRL_Int)dbr;
this.lowerDisplayLimit= ctrl.getLowerDispLimit().doubleValue();
this.upperDisplayLimit=ctrl.getUpperDispLimit().doubleValue();
this.lowerWarningLimit=ctrl.getLowerWarningLimit().doubleValue();
this.upperWarningLimit=ctrl.getUpperWarningLimit().doubleValue();
this.loweCtrlLimit=ctrl.getLowerCtrlLimit().doubleValue();
this.upperCtrlLimit=ctrl.getUpperCtrlLimit().doubleValue();
this.lowerAlarmLimit=ctrl.getLowerAlarmLimit().doubleValue();
this.upperAlarmLimit=ctrl.getUpperAlarmLimit().doubleValue();
this.precision=0;
this.unit=ctrl.getUnits();
updateTypeInfo(pvName, configService);
} else if (dbr instanceof GR) {
logger.debug("Updating metafields for GR pv " + pvName);
final GR ctrl = (GR)dbr;
this.lowerDisplayLimit= ctrl.getLowerDispLimit().doubleValue();
this.upperDisplayLimit=ctrl.getUpperDispLimit().doubleValue();
this.lowerWarningLimit=ctrl.getLowerWarningLimit().doubleValue();
this.upperWarningLimit=ctrl.getUpperWarningLimit().doubleValue();
this.loweCtrlLimit=0;
this.upperCtrlLimit=0;
this.lowerAlarmLimit=ctrl.getLowerAlarmLimit().doubleValue();
this.upperAlarmLimit=ctrl.getUpperAlarmLimit().doubleValue();
this.precision=(dbr instanceof PRECISION)? ((PRECISION)dbr).getPrecision() : 0;
this.unit=ctrl.getUnits();
updateTypeInfo(pvName, configService);
} else {
logger.error("In applyBasicInfo, cannot determine dbr type for " + (dbr != null ? dbr.getClass().getName() : "Null DBR"));
}
}
/**
* set aliaseName
* @param aliaseName
*/
public void setAliasName(String aliaseName) {
this.aliasName=aliaseName;
}
/**
* get lowerAlarmLimit
* @return lowerAlarmLimit <PV Name>.LOLO
*/
public double getLowerAlarmLimit() {
return lowerAlarmLimit;
}
/**
* get loweCtrlLimit
* @return loweCtrlLimit <PV Name>.DRVL
*/
public double getLoweCtrlLimit() {
return loweCtrlLimit;
}
/**
* get lowerDisplayLimit
* @return lowerDisplayLimit <PV Name>.LOPR
*/
public double getLowerDisplayLimit() {
return lowerDisplayLimit;
}
/**
* get lowerWarningLimit
* @return lowerWarningLimit <PV Name>.LOW
*/
public double getLowerWarningLimit() {
return lowerWarningLimit;
}
/**
* get upperAlarmLimit
* @return upperAlarmLimit <PV Name>.HIHI
*/
public double getUpperAlarmLimit() {
return upperAlarmLimit;
}
/**
* get upperCtrlLimit
* @return upperCtrlLimit <PV Name>.DRVH
*/
public double getUpperCtrlLimit() {
return upperCtrlLimit;
}
/**
* get upperDisplayLimit
* @return upperDisplayLimit <PV Name>.HOPR
*/
public double getUpperDisplayLimit() {
return upperDisplayLimit;
}
/**
* get upperWarningLimit
* @return upperWarningLimit <PV Name>.HIGH
*/
public double getUpperWarningLimit() {
return upperWarningLimit;
}
/**
* get precision
* @return precision <PV Name>.PREC
*/
public int getPrecision() {
return precision;
}
/**
* get unit
* @return unit <PV Name>.EGU
*/
public String getUnit() {
return unit;
}
/**
* get aliasName
* @return aliasName <PV Name>.NAME
*/
public String getAliasName() {
return aliasName;
}
/**
* get ArchDBRTypes
* @return ArchDBRTypes
*/
public ArchDBRTypes getArchDBRTypes() {
return archDBRTypes;
}
/**
* get the average event rate in 1 minute
* @return eventRate the average event rate in 1 min
*/
public double getEventRate() {
eventRate=((double)eventCount)/60;
return eventRate;
}
/**
* get the average storage rate in one minute
* @return storageRate average storage rate (bytes per second)
*/
public double getStorageRate() {
storageRate=((double)storageSize)/60;
return storageRate;
}
/**
* get the element count of the pv's value.
* @return count
*/
public int getCount() {
return count;
}
/**
*the pv is vector or not
* @return isVector true if vector, else false;
*/
public boolean isVector() {
return isVector;
}
public String[] getLabel() {
return label;
}
/**
* get total count of event in 1 minute.
* @return eventCount the count of event in one minute
*/
public long getEventCount() {
return eventCount;
}
/**
* get the toal storage size of the event in 1 minute
* @return storageSize toal storage size in one minute
*/
public long getStorageSize() {
return storageSize;
}
public double getSecond() {
return second;
}
/**
* compute the storage rate and the event rate
* @param dbrtimeevent DBRTimeEvent
*/
public void computeRate(DBRTimeEvent dbrtimeevent) {
long now = System.currentTimeMillis();
this.count=dbrtimeevent.getSampleValue().getElementCount();
if(count>1) {
isVector=true;
} else {
isVector=false;
}
long tempmax=Long.MAX_VALUE-100000;
if ((eventCount>tempmax)|(storageSize>tempmax)) {
eventCount=0;
storageSize=0;
startTime= System.currentTimeMillis();
this.second=0.01;
} else {
this.second=(now-this.startTime)/1000;
}
eventCount++;
this.archDBRTypes=dbrtimeevent.getDBRType();
storageSize=storageSize+dbrtimeevent.getRawForm().len;
}
@Override
public String toString() {
String str="host Name:"+hostName+"\r\n";
str=str+"lowerDisplayLimit:"+lowerDisplayLimit+"\r\n";
str=str+"upperDisplayLimit:"+upperDisplayLimit+"\r\n";
str=str+ "lowerWarningLimit:"+lowerWarningLimit+"\r\n";
str=str+ "upperWarningLimit:"+upperWarningLimit+"\r\n";
str=str+ "lowerAlarmLimit:"+lowerAlarmLimit+"\r\n";
str=str+ "upperAlarmLimit:"+upperAlarmLimit+"\r\n";
str=str+ "loweCtrlLimit:"+loweCtrlLimit+"\r\n";
str=str+ "upperCtrlLimit:"+upperCtrlLimit+"\r\n";
str=str+ "precision:"+precision+"\r\n";
str=str+ "unit:"+unit+"\r\n";
str=str+ "isVector:"+isVector+"\r\n";
str=str+ "count:"+count+"\r\n";
str=str+ "storageSize:"+storageSize+"\r\n";
//eventCount
str=str+ "eventCount:"+eventCount+"\r\n";
str=str+ "second:"+second+"\r\n";
str=str+ "aliaseName:"+aliasName+"\r\n";
str=str+ "EventRate:"+this.getEventRate()+"events/second\r\n";
str=str+ "storageRate:"+this.getStorageRate()+"Byte/second\r\n";
str=str+ "DBRtype:"+archDBRTypes+"\r\n";
for(String fieldName : otherMetaInfo.keySet()) {
str=str+ fieldName+":"+ otherMetaInfo.get(fieldName)+"\r\n";
}
return str;
}
/**
* get the time when archiving this pv.
* @return startTime the starting time and the number of milliseconds since 1970/01/01
*/
public long getStartTime() {
return startTime;
}
/**
* set the archiving DBRType for this pv
* @param archDBRTypes ArchDBRTypes
*/
public void setArchDBRTypes(ArchDBRTypes archDBRTypes) {
this.archDBRTypes = archDBRTypes;
}
/**
* save the other info such as MDEL,ADEL
* @param otherMetaInfo a hashmap including the other meta info.
*/
public void setOtherMetaInfo(HashMap<String, String> otherMetaInfo) {
this.otherMetaInfo = otherMetaInfo;
}
/**
* set the lower Alarm Limit
* @param lowerAlarmLimit the lower Alarm Limit
*/
public void setLowerAlarmLimit(double lowerAlarmLimit) {
this.lowerAlarmLimit = lowerAlarmLimit;
}
/**
* set the lower ctrl limit
* @param loweCtrlLimit the lower ctrl limit
*/
public void setLoweCtrlLimit(double loweCtrlLimit) {
this.loweCtrlLimit = loweCtrlLimit;
}
/**
* set the lower display limit
* @param lowerDisplayLimit the lower display limit
*/
public void setLowerDisplayLimit(double lowerDisplayLimit) {
this.lowerDisplayLimit = lowerDisplayLimit;
}
/**
* set the lower warning limit
* @param lowerWarningLimit the lower warning limit
*/
public void setLowerWarningLimit(double lowerWarningLimit) {
this.lowerWarningLimit = lowerWarningLimit;
}
/**
* set the upper alarm limit
* @param upperAlarmLimit the upper alarm limit
*/
public void setUpperAlarmLimit(double upperAlarmLimit) {
this.upperAlarmLimit = upperAlarmLimit;
}
/**
* set the upper ctrl limit
* @param upperCtrlLimit the upper ctrl limit
*/
public void setUpperCtrlLimit(double upperCtrlLimit) {
this.upperCtrlLimit = upperCtrlLimit;
}
/**
* set the upper display limit
* @param upperDisplayLimit the upper display limit
*/
public void setUpperDisplayLimit(double upperDisplayLimit) {
this.upperDisplayLimit = upperDisplayLimit;
}
/**
* set the upper warning limit
* @param upperWarningLimit the upper warning limit
*/
public void setUpperWarningLimit(double upperWarningLimit) {
this.upperWarningLimit = upperWarningLimit;
}
/**
* set the precision
* @param precision the precision
*/
public void setPrecision(int precision) {
this.precision = precision;
}
/**
* set the unit
* @param unit the unit
*/
public void setUnit(String unit) {
this.unit = unit;
}
/**
* set the total event count
* @param eventCount
*/
public void setEventCount(long eventCount) {
this.eventCount = eventCount;
}
/**
* set total storage size of the event until now
* @param storageSize
*/
public void setStorageSize(long storageSize) {
this.storageSize = storageSize;
}
/**
* set the event rate
* @param eventRate the event rate
*/
public void setEventRate(double eventRate) {
this.eventRate = eventRate;
}
/**
* set the storage rate
* @param storageRate storage rate
*/
public void setStorageRate(double storageRate) {
this.storageRate = storageRate;
}
/**
* set the count of pv's value.
* @param count
*/
public void setCount(int count) {
this.count = count;
}
/**
* set this pv to be a vector or not
* @param isVector
*/
public void setVector(boolean isVector) {
this.isVector = isVector;
}
public void setLabel(String[] label) {
this.label = label;
}
public void setSecond(double second) {
this.second = second;
}
/**
* If we detect a change in the units or precision, we update the typeInfo in the configservice.
* This should accommodate changes in EGU and precision.
* However, this should happen rarely or else performance will suffer.
* @param pvName The name of PV.
* @param configService ConfigService
*/
private void updateTypeInfo(String pvName, ConfigService configService) {
PVTypeInfo typeInfo = configService.getTypeInfoForPV(pvName);
boolean updated = false;
if(typeInfo != null) {
if((typeInfo.getUnits() == null && this.unit != null)
|| (typeInfo.getUnits() != null && this.unit != null && !typeInfo.getUnits().equals(this.unit))) {
configLogger.info("Updating units and precision for pv " + pvName + " to " + this.unit + " and " + this.precision);
typeInfo.setUnits(this.unit);
typeInfo.setPrecision(new Double(this.precision));
updated = true;
}
if(typeInfo.getHostName() == null || (typeInfo.getHostName() == null && this.hostName != null && !this.hostName.equals(typeInfo.getHostName()))) {
logger.debug("Updating hostname for pv " + pvName + " to " + this.hostName);
typeInfo.setHostName(this.hostName);
updated = true;
}
if(updated) {
logger.debug("Saving typeinfo in persistence for pv " + pvName);
configService.updateTypeInfoForPV(pvName, typeInfo);
}
}
}
/**
* Add the latest metadata values to the dict
* @param retVal HashMap
*/
public void addToDict(HashMap<String, String> retVal) {
retVal.put("LOPR", Double.toString(lowerDisplayLimit));
retVal.put("HOPR", Double.toString(upperDisplayLimit));
retVal.put("LOW", Double.toString(lowerWarningLimit));
retVal.put("HIGH", Double.toString(upperWarningLimit));
retVal.put("LOLO", Double.toString(lowerAlarmLimit));
retVal.put("HIHI", Double.toString(upperAlarmLimit));
retVal.put("DRVL", Double.toString(loweCtrlLimit));
retVal.put("DRVH", Double.toString(upperCtrlLimit));
retVal.put("PREC", Double.toString(precision));
if(unit != null) { retVal.put("EGU", unit); }
retVal.put("NELM", Integer.toString(count));
for(String fieldName : otherMetaInfo.keySet()) {
retVal.put(fieldName, otherMetaInfo.get(fieldName));
}
if(this.label != null) {
int li= 0;
for(String lbl : this.label) {
retVal.put("ENUM_"+li, lbl);
li++;
}
}
}
public void applyV4BasicInfo(String pvName, PVStructure pvStructure, ConfigService configService) {
// TODO Copy over meta info from the pvStructure...
}
}