VLab Issue #18075 - DR 18336 fix. All keep-alives were being treated as NLDN. Get source from WMO header instead; fixes #18075

Change-Id: I53a392780148de85de9c25fff05c313737137b57

Former-commit-id: 3cf025add9b0c2636a442784bb977601ed7b434e
This commit is contained in:
Andrew Moore 2016-04-22 16:03:57 +00:00
parent c4e85ee05d
commit de50a8ac01
3 changed files with 98 additions and 41 deletions

View file

@ -101,6 +101,7 @@ import com.raytheon.uf.edex.decodertools.core.DecoderTools;
* Aug 04, 2014 3488 bclement added checkBinRange(), rebin() and finalizeRecords()
* Mar 08, 2016 18336 amoore Keep-alive messages should update the legend.
* Apr 07, 2016 DR18763 mgamazaychikov Switched to using LightningWMOHeader.
* May 02, 2016 18336 amoore BinLightningRecord constructor takes source.
*
* </pre>
*
@ -205,7 +206,6 @@ public class BinLightningDecoder {
* and added logic to process both encrypted data and legacy
* data
*/
Collection<LightningStrikePoint> strikes = decodeBinLightningData(
data, pdata, traceId, wmoHdr, baseTime.getTime());
@ -213,17 +213,23 @@ public class BinLightningDecoder {
* Done MOD by Wufeng Zhou
*/
// post processing data - if not keep-alive record
// post processing data
BinLightningRecord report = null;
if (strikes.size() > 0) {
// not a keep-alive
report = LightningGeoFilter.createFilteredRecord(strikes);
} else {
// keep-alive, get the source from WMO header
String source = getSourceFromHeader(wmoHdr);
synchronized (SDF) {
logger.info(traceId
+ ": found keep-alive record of base time ["
+ SDF.format(baseTime.getTime()) + "]");
+ SDF.format(baseTime.getTime())
+ "] and source [" + source + "]");
}
report = new BinLightningRecord(baseTime);
report = new BinLightningRecord(baseTime, source);
}
Collection<BinLightningRecord> records = checkBinRange(report,
@ -395,8 +401,8 @@ public class BinLightningDecoder {
* LightningStrikePoint
*/
public static List<LightningStrikePoint> decodeBinLightningData(
byte[] data, byte[] pdata, String traceId, LightningWMOHeader wmoHdr,
Date dataDate) {
byte[] data, byte[] pdata, String traceId,
LightningWMOHeader wmoHdr, Date dataDate) {
if (pdata == null) { // if data without header not passed, we'll strip
// the WMO header here
LightningWMOHeader header = new LightningWMOHeader(data);
@ -481,8 +487,8 @@ public class BinLightningDecoder {
return new ArrayList<>(0);
}
/*
* not keep-alive record, then check data validity and decode
* into an ArrayList<LightningStrikePoint> of strikes
* not necessarily keep-alive record, then check data validity
* and decode into an ArrayList<LightningStrikePoint> of strikes
*/
if (BinLightningDecoderUtil
.isLightningDataRecords(decryptedData)) {
@ -563,24 +569,9 @@ public class BinLightningDecoder {
switch (decoder.getError()) {
case IBinLightningDecoder.NO_ERROR: {
for (LightningStrikePoint strike : decoder) {
/*
* use WMO Header to distinguish NLDN or GLD360 data because
* no bit-shifted data spec available for GLD360.
* 12/24/2013, WZ The WMO header start string is defined in
* BinLightningAESKey.properties file (normally, GLD360 data
* will have WMO header starts with SFPA41, or SFPA99 for
* test data.)
*/
String gld360WMOHeaderString = BinLightningAESKey
.getProps().getProperty(
"binlightning.gld360WMOHeaderStartString",
"");
if (gld360WMOHeaderString.trim().equals("") == false
&& wmoHdr.getWmoHeader().startsWith(
gld360WMOHeaderString)) {
// GLD360 data based on the setup
strike.setLightSource("GLD");
}
String source = getSourceFromHeader(wmoHdr);
strike.setLightSource(source);
strikes.add(strike);
}
break;
@ -593,6 +584,45 @@ public class BinLightningDecoder {
return strikes;
}
/**
* Get the data source from the given WMO header.
*
* @param wmoHdr
* the header.
* @return the data source according to text from the header.
*/
private static String getSourceFromHeader(LightningWMOHeader wmoHdr) {
/*
* use WMO Header to distinguish NLDN or GLD360 data because no
* bit-shifted data spec available for GLD360. 12/24/2013, WZ The WMO
* header start string is defined in BinLightningAESKey.properties file
* (normally, GLD360 data will have WMO header starts with SFPA41, or
* SFPA99 for test data.)
*/
/*
* continually get the properties locally instead of as a constant
* because the properties file could be changed and reloaded by the
* user.
*/
String gld360WMOHeaderString = BinLightningAESKey.getProps()
.getProperty("binlightning.gld360WMOHeaderStartString", "");
String source = null;
if (gld360WMOHeaderString.trim().equals("") == false
&& wmoHdr.getWmoHeader().startsWith(gld360WMOHeaderString)) {
// GLD360 data based on the setup
source = "GLD";
}
/*
* default source is NLDN, which is the only other option at this time
* for this decoder (5/2/2016, DR 18336). For future sources, add here
* and modify BinLightningAESKey.properties.
*/
return BinLightningRecord.validateSource(source);
}
/**
* Set a trace identifier for the source data.
*

View file

@ -62,6 +62,7 @@ import com.raytheon.uf.common.wmo.WMOTimeParser;
* Jun 19, 2014 3226 bclement added validator callback
* Jul 07, 2015 4581 skorolev Corrected decodeStrikes to avoid BufferUnderflowException.
* Apr 07, 2016 DR18763 mgamazaychikov Switched to using LightningWMOHeader.
* May 02, 2016 18336 amoore Keep-alive messages should update the legend.
*
* </pre>
*
@ -205,13 +206,17 @@ public class TotalLightningDecoder {
pdata = decrypt(wmoHdr, fileName, pdata);
}
List<LightningStrikePoint> strikes = decodeStrikes(fileName, pdata);
BinLightningRecord record;
if (!strikes.isEmpty()) {
BinLightningRecord record = LightningGeoFilter
.createFilteredRecord(strikes);
return new PluginDataObject[] { record };
record = LightningGeoFilter.createFilteredRecord(strikes);
} else {
return new PluginDataObject[0];
// keep-alive record
Calendar baseTime = WMOTimeParser.findDataTime(wmoHdr.getYYGGgg(),
fileName);
record = new BinLightningRecord(baseTime, DATA_SOURCE);
}
return new PluginDataObject[] { record };
}
/**
@ -221,8 +226,8 @@ public class TotalLightningDecoder {
* @return
* @throws DecoderException
*/
private byte[] decrypt(LightningWMOHeader wmoHdr, String fileName, byte[] pdata)
throws DecoderException {
private byte[] decrypt(LightningWMOHeader wmoHdr, String fileName,
byte[] pdata) throws DecoderException {
Calendar baseTime = WMOTimeParser.findDataTime(wmoHdr.getYYGGgg(),
fileName);
pdata = EncryptedBinLightningCipher.prepDataForDecryption(pdata,
@ -236,11 +241,11 @@ public class TotalLightningDecoder {
}
/**
* Extract strike data from raw binary
* Extract strike data from raw binary, ignoring keep-alive strikes.
*
* @param fileName
* @param pdata
* @return
* @return list of lightning strike points, ignoring keep-alive strikes.
* @throws DecoderException
*/
private List<LightningStrikePoint> decodeStrikes(String fileName,

View file

@ -94,6 +94,7 @@ import com.raytheon.uf.common.time.util.TimeUtil;
* Jan 22, 2014 3949 nabowle refactor out default and unknown source constants.
* Jul 23, 2015 2360 rferrel Add name to unique constraint.
* Mar 08, 2016 18336 amoore Keep-alive messages should update the legend.
* May 02, 2016 18336 amoore BinLightningRecord constructor takes source.
*
* </pre>
*
@ -172,9 +173,11 @@ public class BinLightningRecord extends PersistablePluginDataObject implements
*
* @param dateTime
* WMO header base date.
* @param vendorSource
* source of the record.
*/
public BinLightningRecord(final Calendar dateTime) {
source = LightningConstants.DEFAULT_SOURCE;
public BinLightningRecord(final Calendar dateTime, String vendorSource) {
source = vendorSource;
// only data shall be datetime for keep-alive
strikeDataArrays.put(LightningConstants.TIME_DATASET,
@ -321,18 +324,37 @@ public class BinLightningRecord extends PersistablePluginDataObject implements
}
/**
* Extract data source from strike
* Extract data source from strike.
*
* @param strike
* @return
* the strike from which to get data source.
* @return the strike's data source. If null, return
* {@link LightningConstants#DEFAULT_SOURCE}. If empty, return
* {@link LightningConstants#UNKNOWN_SOURCE}.
*/
public static String getDataSource(LightningStrikePoint strike) {
if (strike.getLightSource() == null) {
return validateSource(strike.getLightSource());
}
/**
* Examine the lightning source given, and return a pre-defined constant if
* it is empty or null. Return lightning source as-is if non-null and
* non-empty.
*
* @param iSource
* the lightning source to examine.
* @return a validated lightning source. If null, return
* {@link LightningConstants#DEFAULT_SOURCE}. If empty, return
* {@link LightningConstants#UNKNOWN_SOURCE}. If neither, return the
* original input.
*/
public static String validateSource(String iSource) {
if (iSource == null) {
return LightningConstants.DEFAULT_SOURCE;
} else if (strike.getLightSource().isEmpty()) {
} else if (iSource.isEmpty()) {
return LightningConstants.UNKNOWN_SOURCE;
} else {
return strike.getLightSource();
return iSource;
}
}