ASM #15682 - D-2D: SPC Watches display: Watches do not disappear when expired
Change-Id: I3a29b5b0bb5c75dd5ac5f508391f5806cabf47fa Former-commit-id:d5c086a022
[formerly aca832a81bc18d954eadb51755ce04597cd264df] Former-commit-id:de6e79f9e3
This commit is contained in:
parent
f6748f1e28
commit
9c2545ed64
6 changed files with 530 additions and 7 deletions
|
@ -0,0 +1,29 @@
|
||||||
|
<bundle>
|
||||||
|
<displayList>
|
||||||
|
<displays xsi:type="d2DMapRenderableDisplay"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<descriptor xsi:type="mapDescriptor">
|
||||||
|
<resource>
|
||||||
|
<loadProperties loadWithoutData="true">
|
||||||
|
<capabilities />
|
||||||
|
</loadProperties>
|
||||||
|
<properties isSystemResource="false" isBlinking="false"
|
||||||
|
isMapLayer="false" isHoverOn="false" isVisible="true" />
|
||||||
|
<resourceData xsi:type="wouWcnWatchesResourceData"
|
||||||
|
isUpdatingOnMetadataOnly="false" isRequeryNecessaryOnTimeMatch="true"
|
||||||
|
name="Convective Watches">
|
||||||
|
<metadataMap>
|
||||||
|
<mapping key="phensig">
|
||||||
|
<constraint constraintValue="TO.A,SV.A"
|
||||||
|
constraintType="IN" />
|
||||||
|
</mapping>
|
||||||
|
<mapping key="pluginName">
|
||||||
|
<constraint constraintValue="warning" constraintType="EQUALS" />
|
||||||
|
</mapping>
|
||||||
|
</metadataMap>
|
||||||
|
</resourceData>
|
||||||
|
</resource>
|
||||||
|
</descriptor>
|
||||||
|
</displays>
|
||||||
|
</displayList>
|
||||||
|
</bundle>
|
|
@ -20,8 +20,8 @@
|
||||||
-->
|
-->
|
||||||
<menuTemplate xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
<menuTemplate xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
|
||||||
<contribute xsi:type="bundleItem" file="bundles/ncepHydro/SPCWatchPlot.xml"
|
<contribute xsi:type="bundleItem" file="bundles/ncepHydro/ConvectiveWatchPlot.xml"
|
||||||
menuText="SPC Watches" id="spcWatches">
|
menuText="Convective Watches" id="convectiveWatches">
|
||||||
</contribute>
|
</contribute>
|
||||||
<contribute xsi:type="bundleItem" file="bundles/ncepHydro/SvrWxPlot.xml"
|
<contribute xsi:type="bundleItem" file="bundles/ncepHydro/SvrWxPlot.xml"
|
||||||
menuText="Svr Wx Plot" id="spcWxPlot">
|
menuText="Svr Wx Plot" id="spcWxPlot">
|
||||||
|
|
|
@ -42,6 +42,7 @@ import com.raytheon.viz.core.mode.CAVEMode;
|
||||||
* May 3, 2011 jsanchez Initial creation
|
* May 3, 2011 jsanchez Initial creation
|
||||||
* Oct 25, 2013 2249 rferrel getAvailableTimes always returns a non-empty list.
|
* Oct 25, 2013 2249 rferrel getAvailableTimes always returns a non-empty list.
|
||||||
* Apr 28, 2014 DR 17310 D. Friedman Handle null VTEC fields.
|
* Apr 28, 2014 DR 17310 D. Friedman Handle null VTEC fields.
|
||||||
|
* Aug 28, 2014 ASM #15682 D. Friedman Refactor for WouWcnWatchesResourceData.
|
||||||
*
|
*
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
|
@ -98,13 +99,13 @@ public class WWAResourceData extends AbstractRequestableResourceData {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataTime[] getAvailableTimes() throws VizException {
|
public DataTime[] getAvailableTimes() throws VizException {
|
||||||
DataTime[] available = getAvailableTimes(getMetadataMap(),
|
DataTime[] available = getAvailableWarningTimes(getMetadataMap(),
|
||||||
getBinOffset());
|
getBinOffset());
|
||||||
|
|
||||||
return available;
|
return available;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataTime[] getAvailableTimes(
|
public DataTime[] getAvailableWarningTimes(
|
||||||
Map<String, RequestConstraint> constraintMap, BinOffset binOffset)
|
Map<String, RequestConstraint> constraintMap, BinOffset binOffset)
|
||||||
throws VizException {
|
throws VizException {
|
||||||
DbQueryResponse response = null;
|
DbQueryResponse response = null;
|
||||||
|
@ -116,8 +117,9 @@ public class WWAResourceData extends AbstractRequestableResourceData {
|
||||||
String etn = "etn";
|
String etn = "etn";
|
||||||
String phensig = "phensig";
|
String phensig = "phensig";
|
||||||
String act = "act";
|
String act = "act";
|
||||||
|
String pil = "pil";
|
||||||
request.addFields(new String[] { startTimeField, endTimeField, act,
|
request.addFields(new String[] { startTimeField, endTimeField, act,
|
||||||
etn, phensig });
|
etn, phensig, pil });
|
||||||
|
|
||||||
response = (DbQueryResponse) ThriftClient.sendRequest(request);
|
response = (DbQueryResponse) ThriftClient.sendRequest(request);
|
||||||
if (response.getResults() == null) {
|
if (response.getResults() == null) {
|
||||||
|
@ -137,7 +139,10 @@ public class WWAResourceData extends AbstractRequestableResourceData {
|
||||||
warnRec.setAct((String) map.get(act));
|
warnRec.setAct((String) map.get(act));
|
||||||
warnRec.setPhensig((String) map.get(phensig));
|
warnRec.setPhensig((String) map.get(phensig));
|
||||||
warnRec.setEtn((String) map.get(etn));
|
warnRec.setEtn((String) map.get(etn));
|
||||||
warnings.add(warnRec);
|
warnRec.setPil((String) map.get(pil));
|
||||||
|
if (isRecordTimeImportant(warnRec)) {
|
||||||
|
warnings.add(warnRec);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestConstraint phenSig = constraintMap.get("phensig");
|
RequestConstraint phenSig = constraintMap.get("phensig");
|
||||||
|
@ -165,6 +170,10 @@ public class WWAResourceData extends AbstractRequestableResourceData {
|
||||||
return availableTimes;
|
return availableTimes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean isRecordTimeImportant(AbstractWarningRecord warnRec) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private static TreeSet<DataTime> getWarningStartTimes(
|
private static TreeSet<DataTime> getWarningStartTimes(
|
||||||
ArrayList<AbstractWarningRecord> warnings) {
|
ArrayList<AbstractWarningRecord> warnings) {
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -290,7 +290,7 @@ public class WatchesResource extends AbstractWWAResource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setGeometry(AbstractWarningRecord record) {
|
protected void setGeometry(AbstractWarningRecord record) {
|
||||||
List<String> county = new ArrayList<String>();
|
List<String> county = new ArrayList<String>();
|
||||||
List<String> marinezone = new ArrayList<String>();
|
List<String> marinezone = new ArrayList<String>();
|
||||||
List<Geometry> geometries = new ArrayList<Geometry>();
|
List<Geometry> geometries = new ArrayList<Geometry>();
|
||||||
|
|
|
@ -0,0 +1,429 @@
|
||||||
|
package com.raytheon.viz.warnings.rsc;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
|
import com.raytheon.uf.common.dataplugin.warning.AbstractWarningRecord;
|
||||||
|
import com.raytheon.uf.common.dataplugin.warning.WarningRecord.WarningAction;
|
||||||
|
import com.raytheon.uf.common.time.ISimulatedTimeChangeListener;
|
||||||
|
import com.raytheon.uf.common.time.SimulatedTime;
|
||||||
|
import com.raytheon.uf.viz.core.IGraphicsTarget;
|
||||||
|
import com.raytheon.uf.viz.core.drawables.FillPatterns;
|
||||||
|
import com.raytheon.uf.viz.core.drawables.IShadedShape;
|
||||||
|
import com.raytheon.uf.viz.core.exception.VizException;
|
||||||
|
import com.raytheon.uf.viz.core.rsc.LoadProperties;
|
||||||
|
import com.raytheon.viz.core.rsc.jts.JTSCompiler;
|
||||||
|
import com.raytheon.viz.core.rsc.jts.JTSCompiler.PointStyle;
|
||||||
|
import com.vividsolutions.jts.geom.Geometry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays WOUs updated by WCNs
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
*
|
||||||
|
* SOFTWARE HISTORY
|
||||||
|
*
|
||||||
|
* Date Ticket# Engineer Description
|
||||||
|
* ------------ ---------- ----------- --------------------------
|
||||||
|
* 2014-08-28 ASM #15682 D. Friemdan Initial creation
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class WouWcnWatchesResource extends WatchesResource implements ISimulatedTimeChangeListener {
|
||||||
|
|
||||||
|
private static Timer timer;
|
||||||
|
|
||||||
|
private TimerTask timerTask;
|
||||||
|
|
||||||
|
// If this is changed to use the maps database, could probably be static
|
||||||
|
private Map<String, Set<String>> cwaUgcMap = new HashMap<String, Set<String>>();
|
||||||
|
|
||||||
|
static final ThreadLocal<SimpleDateFormat> sdf = new ThreadLocal<SimpleDateFormat>() {
|
||||||
|
@Override protected SimpleDateFormat initialValue() {
|
||||||
|
return new SimpleDateFormat("yyyyMMddHHmm");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public WouWcnWatchesResource(WWAResourceData data, LoadProperties props) {
|
||||||
|
super(data, props);
|
||||||
|
comparator = WouWcnWatchesComparator.getInstance();
|
||||||
|
resourceName = "Watches";
|
||||||
|
}
|
||||||
|
|
||||||
|
private AbstractWarningRecord getPreviousRecordForEvent(AbstractWarningRecord rec) {
|
||||||
|
String phenSig = rec.getPhensig();
|
||||||
|
String etn = rec.getEtn();
|
||||||
|
if (phenSig == null || etn == null)
|
||||||
|
return null;
|
||||||
|
AbstractWarningRecord best = null;
|
||||||
|
for (WarningEntry e : entryMap.values()) {
|
||||||
|
if (!phenSig.equals(e.record.getPhensig()) ||
|
||||||
|
!etn.equals(e.record.getEtn()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (best == null || WouWcnWatchesComparator.getInstance().
|
||||||
|
compare(best, e.record) < 0) {
|
||||||
|
best = e.record;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> maskCwaUgcs(Set<String> ugcs, AbstractWarningRecord rec) {
|
||||||
|
Set<String> cwaUgcs = getUgcsForCwa(rec.getXxxid());
|
||||||
|
if (cwaUgcs != null) {
|
||||||
|
HashSet<String> result = new HashSet<String>(ugcs);
|
||||||
|
result.removeAll(cwaUgcs);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return ugcs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> getUgcsForCwa(String cwa) {
|
||||||
|
return cwaUgcMap.get(cwa.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> safe(Set<String> set) {
|
||||||
|
return set != null ? set : new HashSet<String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateDisplay(IGraphicsTarget target) throws VizException {
|
||||||
|
if (recordsToLoad.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
List<AbstractWarningRecord> mergedWatches = mergeWatches(recordsToLoad);
|
||||||
|
for (AbstractWarningRecord watchRec : mergedWatches) {
|
||||||
|
/* If these things are missing, we can't do anything with the warning. */
|
||||||
|
if (watchRec.getPhensig() == null || watchRec.getEtn() == null ||
|
||||||
|
watchRec.getIssueTime() == null || watchRec.getStartTime() == null ||
|
||||||
|
watchRec.getEndTime() == null || watchRec.getXxxid() == null ||
|
||||||
|
watchRec.getWmoid() == null || watchRec.getAct() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
WarningAction watchAct = WarningAction.valueOf(watchRec.getAct());
|
||||||
|
|
||||||
|
AbstractWarningRecord createShape = null;
|
||||||
|
boolean isWOU = "WOU".equals(watchRec.getPil());
|
||||||
|
|
||||||
|
AbstractWarningRecord prevRec = getPreviousRecordForEvent(watchRec);
|
||||||
|
Set<String> prevUgcs = new HashSet<String>(safe(
|
||||||
|
prevRec != null ? prevRec.getUgcZones() : null));
|
||||||
|
Set<String> newUgcs = null;
|
||||||
|
|
||||||
|
if (watchAct == WarningAction.NEW) {
|
||||||
|
if (isWOU) {
|
||||||
|
createShape = watchRec;
|
||||||
|
} else {
|
||||||
|
noteCwaUgcs(watchRec);
|
||||||
|
// As per requirements, we do not create frames for these.
|
||||||
|
}
|
||||||
|
} else if (watchAct == WarningAction.CON && isWOU) {
|
||||||
|
// As per requirements, we do not create frames for these.
|
||||||
|
} else if (watchAct == WarningAction.CON) {
|
||||||
|
/* No need to do anything because we really only care about
|
||||||
|
* the segments paired with the CON.
|
||||||
|
*/
|
||||||
|
} else if (watchAct == WarningAction.CAN) {
|
||||||
|
/* Not really expecting this for a WOU, but shouldn't cause
|
||||||
|
* a problem if there is one.
|
||||||
|
*/
|
||||||
|
newUgcs = prevUgcs;
|
||||||
|
newUgcs.removeAll(safe(watchRec.getUgcZones()));
|
||||||
|
createShape = watchRec;
|
||||||
|
} else if (watchAct == WarningAction.EXA || watchAct == WarningAction.EXB) {
|
||||||
|
if (!isWOU) {
|
||||||
|
noteCwaUgcs(watchRec);
|
||||||
|
}
|
||||||
|
newUgcs = prevUgcs;
|
||||||
|
newUgcs.addAll(safe(watchRec.getUgcZones()));
|
||||||
|
createShape = watchRec;
|
||||||
|
} else if (watchAct == WarningAction.EXP) {
|
||||||
|
if (isWOU) {
|
||||||
|
if (prevRec != null) {
|
||||||
|
if (! prevRec.getEndTime().equals(watchRec.getEndTime())) {
|
||||||
|
prevRec.setEndTime(watchRec.getEndTime());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Ideally we do not need to create a shape, but if we do
|
||||||
|
* not and time matching creates a frame for an EXP that is
|
||||||
|
* issued before the expiration time, the warning would show
|
||||||
|
* as still active on that frame.
|
||||||
|
*/
|
||||||
|
newUgcs = new HashSet<String>();
|
||||||
|
createShape = watchRec;
|
||||||
|
} else {
|
||||||
|
newUgcs = maskCwaUgcs(prevUgcs, watchRec);
|
||||||
|
createShape = watchRec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (watchAct == WarningAction.EXT || watchAct == WarningAction.EXB) {
|
||||||
|
/* This resource does not handle different expiration times
|
||||||
|
* for different UGCs.
|
||||||
|
*
|
||||||
|
* Also assuming this does not add/remove UGCs.
|
||||||
|
*/
|
||||||
|
if (prevRec != null && watchRec.getEndTime() != null) {
|
||||||
|
if (isWOU && watchRec.getUgcZones() != null && watchRec.getUgcZones().isEmpty()) {
|
||||||
|
/*
|
||||||
|
* This probably does not actually happen, but this
|
||||||
|
* is the only way we can support shortening the
|
||||||
|
* expiration time with the current design.
|
||||||
|
*/
|
||||||
|
prevRec.setEndTime(watchRec.getEndTime());
|
||||||
|
} else {
|
||||||
|
if (prevRec.getEndTime().before(watchRec.getEndTime())) {
|
||||||
|
prevRec.setEndTime(watchRec.getEndTime());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (createShape != null) {
|
||||||
|
if (newUgcs != null)
|
||||||
|
createShape.setUgcZones(newUgcs);
|
||||||
|
else if (createShape.getUgcZones() == null)
|
||||||
|
createShape.setUgcZones(new HashSet<String>());
|
||||||
|
insertShape(target, createShape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
recordsToLoad.clear();
|
||||||
|
scheduleNextTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initShape(IGraphicsTarget target,
|
||||||
|
AbstractWarningRecord record) throws VizException {
|
||||||
|
String key = getEntryMapKey(record);
|
||||||
|
WarningEntry entry = entryMap.get(key);
|
||||||
|
if (entry != null) {
|
||||||
|
createShape(target, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void insertShape(IGraphicsTarget target, AbstractWarningRecord record) throws VizException {
|
||||||
|
String key = getEntryMapKey(record);
|
||||||
|
WarningEntry entry = entryMap.get(key);
|
||||||
|
if (entry == null) {
|
||||||
|
entry = new WarningEntry();
|
||||||
|
entryMap.put(key, entry);
|
||||||
|
}
|
||||||
|
entry.record = record; // ...possibly replacing an existing record
|
||||||
|
if (! record.getUgcZones().isEmpty()) {
|
||||||
|
setGeometry(record);
|
||||||
|
} else {
|
||||||
|
entry.record.setGeometry(null);
|
||||||
|
}
|
||||||
|
createShape(target, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void createShape(IGraphicsTarget target, WarningEntry entry) throws VizException {
|
||||||
|
if (entry.shadedShape != null) {
|
||||||
|
entry.shadedShape.dispose();
|
||||||
|
entry.shadedShape = null;
|
||||||
|
}
|
||||||
|
AbstractWarningRecord record = entry.record;
|
||||||
|
if (record.getGeometry() != null) {
|
||||||
|
IShadedShape ss = target.createShadedShape(false,
|
||||||
|
descriptor.getGridGeometry(), false);
|
||||||
|
Geometry geo = (Geometry) record.getGeometry().clone();
|
||||||
|
JTSCompiler jtsCompiler = new JTSCompiler(ss, null,
|
||||||
|
this.descriptor, PointStyle.CROSS);
|
||||||
|
jtsCompiler.handle(geo, color);
|
||||||
|
ss.setFillPattern(FillPatterns.getGLPattern(record.getPhen()
|
||||||
|
.equals("TO") ? "VERTICAL" : "HORIZONTAL"));
|
||||||
|
ss.compile();
|
||||||
|
entry.shadedShape = ss;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Groups all the ugc zones with the same action, phensig, ETN, site, and
|
||||||
|
* issuance time.
|
||||||
|
*/
|
||||||
|
protected List<AbstractWarningRecord> mergeWatches(
|
||||||
|
List<AbstractWarningRecord> watchrecs) {
|
||||||
|
SimpleDateFormat sdfi = sdf.get();
|
||||||
|
|
||||||
|
Map<String, AbstractWarningRecord> watches = new HashMap<String, AbstractWarningRecord>();
|
||||||
|
for (AbstractWarningRecord watchrec : watchrecs) {
|
||||||
|
if (watchrec.getIssueTime() == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
String key = watchrec.getAct() + '.' + watchrec.getPhensig() + '.'
|
||||||
|
+ watchrec.getEtn() + '.' + watchrec.getOfficeid() + '.'
|
||||||
|
+ sdfi.format(watchrec.getIssueTime().getTime());
|
||||||
|
AbstractWarningRecord watch = watches.get(key);
|
||||||
|
if (watch == null) {
|
||||||
|
watch = watchrec;
|
||||||
|
watches.put(key, watch);
|
||||||
|
} else {
|
||||||
|
Set<String> ugcZones = watch.getUgcZones();
|
||||||
|
if (ugcZones != null) {
|
||||||
|
ugcZones.addAll(watchrec.getUgcZones());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<AbstractWarningRecord> mergedWatches = new ArrayList<AbstractWarningRecord>(
|
||||||
|
watches.values());
|
||||||
|
Collections.sort(mergedWatches, comparator);
|
||||||
|
|
||||||
|
return mergedWatches;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getEntryMapKey(AbstractWarningRecord rec) {
|
||||||
|
return sdf.get().format(rec.getIssueTime().getTime()) + '.'
|
||||||
|
+ rec.getWmoid() + '.' + rec.getPhensig() + '.' + rec.getEtn();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getEventKey(WarningEntry entry) {
|
||||||
|
AbstractWarningRecord r = entry.record;
|
||||||
|
return r.getPhensig() + '.' + r.getEtn();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void noteCwaUgcs(AbstractWarningRecord watchRec) {
|
||||||
|
String siteKey = watchRec.getXxxid();
|
||||||
|
Set<String> recUgcs = watchRec.getUgcZones();
|
||||||
|
if (siteKey == null || recUgcs == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
synchronized (cwaUgcMap) {
|
||||||
|
Set<String> ugcs = cwaUgcMap.get(siteKey);
|
||||||
|
if (ugcs == null) {
|
||||||
|
ugcs = new HashSet<String>();
|
||||||
|
cwaUgcMap.put(siteKey, ugcs);
|
||||||
|
}
|
||||||
|
ugcs.addAll(recUgcs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void disposeInternal() {
|
||||||
|
synchronized(this) {
|
||||||
|
if (timerTask != null)
|
||||||
|
timerTask.cancel();
|
||||||
|
}
|
||||||
|
super.disposeInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleNextTime() {
|
||||||
|
/* TODO: This is a race condition. Need the last frame time,
|
||||||
|
* but getLastFrameTimeRange() is also a race condition. So really need
|
||||||
|
* last drawn last frame time, but LAST_FRAME_ADJ is an hour ahead??!
|
||||||
|
*/
|
||||||
|
long vnow = SimulatedTime.getSystemTime().getMillis();
|
||||||
|
AbstractWarningRecord best = null;
|
||||||
|
for (WarningEntry entry : entryMap.values()) {
|
||||||
|
AbstractWarningRecord rec = entry.record;
|
||||||
|
if (rec.getEndTime().getTimeInMillis() >= vnow &&
|
||||||
|
(best == null || rec.getEndTime().before(best.getEndTime()))) {
|
||||||
|
best = rec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (best != null) {
|
||||||
|
scheduleTimer(best.getEndTime().getTimeInMillis() - vnow);
|
||||||
|
} else {
|
||||||
|
scheduleTimer(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void scheduleTimer(long delay) {
|
||||||
|
if (timerTask != null) {
|
||||||
|
timerTask.cancel();
|
||||||
|
}
|
||||||
|
if (delay >= 0) {
|
||||||
|
timerTask = new WatchesTimerTask();
|
||||||
|
getTimer().schedule(timerTask, delay);
|
||||||
|
} else {
|
||||||
|
timerTask = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Timer getTimer() {
|
||||||
|
if (timer == null) {
|
||||||
|
synchronized (WouWcnWatchesResource.class) {
|
||||||
|
if (timer == null) {
|
||||||
|
timer = new Timer(WouWcnWatchesResource.class.getName() + " Timer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return timer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void timechanged() {
|
||||||
|
issueRefresh();
|
||||||
|
scheduleNextTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class WatchesTimerTask extends TimerTask {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
timechanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class WouWcnWatchesComparator implements Comparator<AbstractWarningRecord> {
|
||||||
|
|
||||||
|
static final WouWcnWatchesComparator instance = new WouWcnWatchesComparator();
|
||||||
|
|
||||||
|
public static Comparator<AbstractWarningRecord> getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(AbstractWarningRecord a, AbstractWarningRecord b) {
|
||||||
|
int r;
|
||||||
|
Calendar ca = a.getIssueTime();
|
||||||
|
Calendar cb = b.getIssueTime();
|
||||||
|
if (ca == null) {
|
||||||
|
if (cb == null)
|
||||||
|
r = 0;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
} else if (cb == null)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
r = ca.compareTo(cb);
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
// The point of this is to handle the BBB field, but it makes the TTAAii part significant too...
|
||||||
|
String sa = safeWmo(a);
|
||||||
|
String sb = safeWmo(b);
|
||||||
|
r = sa.compareTo(sb);
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = a.getSeg() - b.getSeg();
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String safeWmo(AbstractWarningRecord record) {
|
||||||
|
String wmo = record.getWmoid();
|
||||||
|
return wmo != null ? wmo : "TTAA00 CCCC 000000";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package com.raytheon.viz.warnings.rsc;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
|
||||||
|
import com.raytheon.uf.common.dataplugin.PluginDataObject;
|
||||||
|
import com.raytheon.uf.common.dataplugin.warning.AbstractWarningRecord;
|
||||||
|
import com.raytheon.uf.common.dataplugin.warning.WarningRecord.WarningAction;
|
||||||
|
import com.raytheon.uf.viz.core.exception.VizException;
|
||||||
|
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
|
||||||
|
import com.raytheon.uf.viz.core.rsc.LoadProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays WOUs updated by WCNs
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
*
|
||||||
|
* SOFTWARE HISTORY
|
||||||
|
*
|
||||||
|
* Date Ticket# Engineer Description
|
||||||
|
* ------------ ---------- ----------- --------------------------
|
||||||
|
* 2014-08-28 ASM #15682 D. Friemdan Initial creation
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@XmlAccessorType(XmlAccessType.NONE)
|
||||||
|
public class WouWcnWatchesResourceData extends WWAResourceData {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AbstractVizResource<?, ?> constructResource(
|
||||||
|
LoadProperties loadProperties, PluginDataObject[] objects)
|
||||||
|
throws VizException {
|
||||||
|
// add records
|
||||||
|
records = new ArrayList<AbstractWarningRecord>(objects.length);
|
||||||
|
for (int i = 0; i < objects.length; i++) {
|
||||||
|
AbstractWarningRecord r = (AbstractWarningRecord) objects[i];
|
||||||
|
records.add(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new WouWcnWatchesResource(this, loadProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isRecordTimeImportant(AbstractWarningRecord warnRec) {
|
||||||
|
WarningAction act = WarningAction.valueOf(warnRec.getAct());
|
||||||
|
if (("WOU".equals(warnRec.getPil()) && WarningAction.CON == act) ||
|
||||||
|
("WCN".equals(warnRec.getPil()) && WarningAction.NEW == act)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return super.isRecordTimeImportant(warnRec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue