From 93e423e9b0e084931841150a13e221603f35ab27 Mon Sep 17 00:00:00 2001 From: Nathan Bowler Date: Thu, 18 Jun 2015 16:25:56 -0400 Subject: [PATCH] Omaha #4379 Display live CWAs Change-Id: I39e1243d9fbc8d3206dea42f91039fc90db9f2ac Former-commit-id: 7c711723a8b3cc3ddab6523da7e9219bfb9efe72 --- .../raytheon/uf/viz/cwa/rsc/CWAResource.java | 206 +++++++++++++----- .../uf/viz/cwa/rsc/CWAResourceData.java | 35 ++- 2 files changed, 182 insertions(+), 59 deletions(-) diff --git a/cave/com.raytheon.uf.viz.cwa/src/com/raytheon/uf/viz/cwa/rsc/CWAResource.java b/cave/com.raytheon.uf.viz.cwa/src/com/raytheon/uf/viz/cwa/rsc/CWAResource.java index 6f455f0f60..5060b0b48a 100644 --- a/cave/com.raytheon.uf.viz.cwa/src/com/raytheon/uf/viz/cwa/rsc/CWAResource.java +++ b/cave/com.raytheon.uf.viz.cwa/src/com/raytheon/uf/viz/cwa/rsc/CWAResource.java @@ -20,10 +20,16 @@ package com.raytheon.uf.viz.cwa.rsc; 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 org.opengis.referencing.crs.CoordinateReferenceSystem; @@ -35,7 +41,10 @@ import com.raytheon.uf.common.geospatial.ReferencedCoordinate; import com.raytheon.uf.common.pointdata.PointDataContainer; import com.raytheon.uf.common.pointdata.PointDataView; import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.common.time.ISimulatedTimeChangeListener; +import com.raytheon.uf.common.time.SimulatedTime; import com.raytheon.uf.common.time.util.TimeUtil; +import com.raytheon.uf.viz.core.AbstractTimeMatcher; import com.raytheon.uf.viz.core.DrawableString; import com.raytheon.uf.viz.core.IGraphicsTarget; import com.raytheon.uf.viz.core.drawables.IFont; @@ -46,11 +55,12 @@ import com.raytheon.uf.viz.core.drawables.PaintProperties; import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.uf.viz.core.map.MapDescriptor; import com.raytheon.uf.viz.core.rsc.AbstractVizResource; -import com.raytheon.uf.viz.core.rsc.IResourceDataChanged; +import com.raytheon.uf.viz.core.rsc.IResourceDataChanged.ChangeType; import com.raytheon.uf.viz.core.rsc.LoadProperties; import com.raytheon.uf.viz.core.rsc.capabilities.ColorableCapability; import com.raytheon.uf.viz.core.rsc.capabilities.MagnificationCapability; import com.raytheon.uf.viz.core.rsc.capabilities.OutlineCapability; +import com.raytheon.uf.viz.core.time.TimeMatchingJob; import com.raytheon.viz.pointdata.PointDataRequest; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.GeometryFactory; @@ -70,6 +80,7 @@ import com.vividsolutions.jts.geom.Polygon; * Jun 10,2011 9744 cjeanbap Added Magnification, Outline, and Density * compabilities. * May 11, 2015 4379 nabowle Display all current CWAs for each frame. + * Jun 15, 2015 4379 nabowle Make last frame a live frame. * * * @author jsanchez @@ -77,11 +88,7 @@ import com.vividsolutions.jts.geom.Polygon; */ public class CWAResource extends AbstractVizResource implements - IResourceDataChanged { - - protected DataTime displayedDataTime; - - private Map frameMap; + ISimulatedTimeChangeListener { private static final String LATS = "latitudes"; @@ -97,8 +104,6 @@ public class CWAResource extends private static final String CWA_NAME = "Conus Center Weather Advisory"; - private static final String ID = "id"; - private static final String DATA_TIME = "dataTime"; private static final String REF_TIME = "refTime"; @@ -107,6 +112,16 @@ public class CWAResource extends private static final String START = DATA_TIME + ".validPeriod.start"; + protected static RefreshTimerTask refreshTask; + + protected static Timer refreshTimer; + + protected DataTime displayedDataTime; + + private Map frameMap; + + private CWAFrame liveFrame = new CWAFrame(now()); + private IFont font; private class CWAFrame implements IRenderable { @@ -125,14 +140,6 @@ public class CWAResource extends strings = new ArrayList(); } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.viz.core.drawables.IRenderable#paint(com.raytheon - * .uf.viz.core.IGraphicsTarget, - * com.raytheon.uf.viz.core.drawables.PaintProperties) - */ @Override public void paint(IGraphicsTarget target, PaintProperties paintProps) throws VizException { @@ -164,7 +171,7 @@ public class CWAResource extends */ private void updateFrame(IGraphicsTarget target, PaintProperties paintProps) throws VizException { - Map constraints = new HashMap(); + Map constraints = new HashMap<>(); String startTime = TimeUtil.formatToSqlTimestamp(time.getRefTime()); // Select CWAs whose valid period contains this frame's start time. @@ -179,20 +186,12 @@ public class CWAResource extends constraints.put(END, constraint); // Request the point data - PointDataContainer pdc = PointDataRequest + this.pdc = PointDataRequest .requestPointDataAllLevels((DataTime) null, resourceData.getMetadataMap().get("pluginName") .getConstraintValue(), getParameters(), null, constraints); - if (this.pdc == null) { - this.pdc = pdc; - } else { - this.pdc.combine(pdc); - this.pdc.setCurrentSz(this.pdc.getAllocatedSz()); - this.framePdvs = null; - } - if (wfs != null) { wfs.dispose(); } @@ -200,7 +199,10 @@ public class CWAResource extends wfs = target.createWireframeShape(false, descriptor); - if (this.framePdvs == null) { + if (this.pdc == null) { + // nothing met the query restraints + this.framePdvs = Collections.emptyList(); + } else { this.framePdvs = getPDVs(); } @@ -291,6 +293,36 @@ public class CWAResource extends } } + protected static class RefreshTimerTask extends TimerTask { + + private final Set resourceSet = new HashSet<>(); + + @Override + public void run() { + List rscs; + synchronized (resourceSet) { + rscs = new ArrayList<>(resourceSet); + } + for (CWAResource rsc : rscs) { + rsc.updateLiveFrame(now()); + rsc.issueRefresh(); + rsc.redoTimeMatching(); + } + } + + public void addResource(CWAResource rsc) { + synchronized (resourceSet) { + resourceSet.add(rsc); + } + } + + public void removeResource(CWAResource rsc) { + synchronized (resourceSet) { + resourceSet.remove(rsc); + } + } + } + protected CWAResource(CWAResourceData resourceData, LoadProperties loadProperties) { super(resourceData, loadProperties); @@ -298,19 +330,66 @@ public class CWAResource extends this.dataTimes = new ArrayList(); } + /** + * Cancel the heart beat timer task + * + * @param resource + */ + protected static void cancelRefreshTask(CWAResource resource) { + synchronized (RefreshTimerTask.class) { + if (refreshTask != null) { + refreshTask.removeResource(resource); + if (refreshTask.resourceSet.isEmpty()) { + refreshTimer.cancel(); + refreshTimer = null; + refreshTask = null; + } + } + } + } + + /** + * schedule the heart beat for the next minute + */ + protected static void scheduleRefreshTask(CWAResource resource) { + synchronized (RefreshTimerTask.class) { + if (refreshTask == null) { + refreshTimer = new Timer(true); + refreshTask = new RefreshTimerTask(); + + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.MINUTE, 1); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + + refreshTimer.scheduleAtFixedRate(refreshTask, cal.getTime(), + TimeUtil.MILLIS_PER_MINUTE); + } + refreshTask.addResource(resource); + } + } + + /** + * Get the current/simulated time to the minute. Seconds and Milliseconds + * will be zero so a consistent time can be used each minute when retrieving + * from the frame map. + * + * @return + */ + public static DataTime now() { + Calendar cal = Calendar.getInstance(); + cal.setTime(SimulatedTime.getSystemTime().getTime()); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + + return new DataTime(cal); + } + @Override public String getName() { return CWA_NAME; } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.viz.core.rsc.AbstractVizResource#paintInternal(com.raytheon - * .uf.viz.core.IGraphicsTarget, - * com.raytheon.uf.viz.core.drawables.PaintProperties) - */ @Override protected void paintInternal(IGraphicsTarget target, PaintProperties paintProps) throws VizException { @@ -329,6 +408,7 @@ public class CWAResource extends @Override protected void disposeInternal() { + cancelRefreshTask(this); if (font != null) { font.dispose(); font = null; @@ -346,6 +426,9 @@ public class CWAResource extends protected void initInternal(IGraphicsTarget target) throws VizException { this.font = target.initializeFont("Monospace", 11, new Style[] { Style.ITALIC }); + updateLiveFrame(now()); + scheduleRefreshTask(this); + SimulatedTime.getSystemTime().addSimulatedTimeChangeListener(this); } @Override @@ -464,18 +547,13 @@ public class CWAResource extends } } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.viz.core.rsc.IResourceDataChanged#resourceChanged(com - * .raytheon.uf.viz.core.rsc.IResourceDataChanged.ChangeType, - * java.lang.Object) + /** + * Handle Data Updates by adding the record and refreshing the display. */ @Override - public void resourceChanged(ChangeType type, Object object) { + protected void resourceDataChanged(ChangeType type, Object updateObject) { if (type == ChangeType.DATA_UPDATE) { - PluginDataObject[] pdo = (PluginDataObject[]) object; + PluginDataObject[] pdo = (PluginDataObject[]) updateObject; for (PluginDataObject p : pdo) { if (p instanceof CWARecord) { addRecord((CWARecord) p); @@ -485,17 +563,43 @@ public class CWAResource extends issueRefresh(); } - /* - * (non-Javadoc) - * - * @see - * com.raytheon.uf.viz.core.rsc.AbstractVizResource#project(org.opengis. - * referencing.crs.CoordinateReferenceSystem) - */ @Override public void project(CoordinateReferenceSystem crs) throws VizException { frameMap.get(displayedDataTime).wfs.dispose(); frameMap.get(displayedDataTime).wfs = null; } + /** + * Update the live frame's time and mapping. + */ + protected void updateLiveFrame(DataTime time) { + synchronized (this.frameMap) { + this.frameMap.remove(this.liveFrame.time); + this.liveFrame.time = time; + this.liveFrame.dispose(); + this.liveFrame.wfs = null; + this.frameMap.put(time, this.liveFrame); + } + } + + /** + * Redo the time matching + */ + protected void redoTimeMatching() { + AbstractTimeMatcher timeMatcher = this.getDescriptor().getTimeMatcher(); + if (timeMatcher != null) { + timeMatcher.redoTimeMatching(this); + TimeMatchingJob.scheduleTimeMatch(this.getDescriptor()); + } + } + + /** + * Updates the live frame to the current time set. + */ + @Override + public void timechanged() { + updateLiveFrame(now()); + issueRefresh(); + redoTimeMatching(); + } } diff --git a/cave/com.raytheon.uf.viz.cwa/src/com/raytheon/uf/viz/cwa/rsc/CWAResourceData.java b/cave/com.raytheon.uf.viz.cwa/src/com/raytheon/uf/viz/cwa/rsc/CWAResourceData.java index b083b7000e..f410f8a59c 100644 --- a/cave/com.raytheon.uf.viz.cwa/src/com/raytheon/uf/viz/cwa/rsc/CWAResourceData.java +++ b/cave/com.raytheon.uf.viz.cwa/src/com/raytheon/uf/viz/cwa/rsc/CWAResourceData.java @@ -1,24 +1,28 @@ /** * This software was developed and / or modified by Raytheon Company, * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * + * * U.S. EXPORT CONTROLLED TECHNICAL DATA * This software product contains export-restricted data whose * export/transfer/disclosure is restricted by U.S. law. Dissemination * to non-U.S. persons whether in the United States or abroad requires * an export license or other authorization. - * + * * Contractor Name: Raytheon Company * Contractor Address: 6825 Pine Street, Suite 340 * Mail Stop B8 * Omaha, NE 68106 * 402.291.0100 - * + * * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ package com.raytheon.uf.viz.cwa.rsc; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlType; @@ -28,6 +32,7 @@ import com.raytheon.uf.common.dataplugin.cwa.CWARecord; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.common.time.DataTime; import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.uf.viz.core.rsc.AbstractRequestableResourceData; import com.raytheon.uf.viz.core.rsc.AbstractVizResource; @@ -35,16 +40,17 @@ import com.raytheon.uf.viz.core.rsc.LoadProperties; /** * ResourceData for Center Weather Advisory data - * + * *
- * 
+ *
  * SOFTWARE HISTORY
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
  * Feb 4, 2010             jsanchez     Initial creation
- * 
+ * Jun 16, 2015 4379       nabowle      Add the current time to {@link #getAvailableTimes()}.
+ *
  * 
- * + * * @author jsanchez * @version 1.0 */ @@ -55,7 +61,7 @@ public class CWAResourceData extends AbstractRequestableResourceData { .getHandler(CWAResourceData.class); public CWAResourceData() { - // TODO Auto-generated constructor stub + super(); } @Override @@ -89,4 +95,17 @@ public class CWAResourceData extends AbstractRequestableResourceData { } return rsc; } + + /** + * Return a set of available times for the given resource data. The current + * time is appended to the list so CWAResource can display a live view of + * active CWAs. + */ + @Override + public DataTime[] getAvailableTimes() throws VizException { + List times = new ArrayList<>(); + times.addAll(Arrays.asList(super.getAvailableTimes())); + times.add(CWAResource.now()); + return times.toArray(new DataTime[0]); + } }