Issue #1096 fix memory leaks in CcfpResource

Change-Id: Icccd4d3811327b9a1dcfdf6a5a2cc714ff92afbc

Former-commit-id: 047441f91c [formerly 5e9d7763442ab91cb8d33c16139eb5bca9b033ea]
Former-commit-id: 73f428e4d5
This commit is contained in:
Nate Jensen 2012-08-23 18:18:23 -05:00
parent f3a33e3df4
commit 7b62f6ac75
2 changed files with 105 additions and 43 deletions

View file

@ -24,6 +24,7 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -63,6 +64,7 @@ import com.vividsolutions.jts.geom.Point;
* Date Ticket# Engineer Description * Date Ticket# Engineer Description
* ------------ ---------- ----------- -------------------------- * ------------ ---------- ----------- --------------------------
* Sep 22, 2009 3072 bsteffen Initial creation * Sep 22, 2009 3072 bsteffen Initial creation
* Aug 23, 2012 1096 njensen Fixed memory leaks
* *
* </pre> * </pre>
* *
@ -161,8 +163,10 @@ public class CcfpResource extends
} }
private void disposeFrames() { private void disposeFrames() {
for (DisplayFrame frame : frames.values()) { synchronized (frames) {
frame.dispose(); for (DisplayFrame frame : frames.values()) {
frame.dispose();
}
} }
} }
@ -180,11 +184,15 @@ public class CcfpResource extends
@Override @Override
public String inspect(ReferencedCoordinate coord) throws VizException { public String inspect(ReferencedCoordinate coord) throws VizException {
if (frames.get(this.displayedDataTime) == null) { DisplayFrame frame = null;
synchronized (frames) {
frame = frames.get(this.displayedDataTime);
}
if (frame == null) {
return ""; return "";
} }
StringBuilder res = new StringBuilder(); StringBuilder res = new StringBuilder();
for (CcfpRecord record : frames.get(this.displayedDataTime).records) { for (CcfpRecord record : frame.records) {
// Check if we have an area we are rendering // Check if we have an area we are rendering
if (isPaintingArea(record)) { if (isPaintingArea(record)) {
try { try {
@ -216,15 +224,20 @@ public class CcfpResource extends
*/ */
private void updateRecords(IGraphicsTarget target, private void updateRecords(IGraphicsTarget target,
PaintProperties paintProps) throws VizException { PaintProperties paintProps) throws VizException {
DisplayFrame frame = frames.get(this.displayedDataTime); DisplayFrame frame = null;
if (frame == null) { synchronized (frames) {
frame = new DisplayFrame(); frame = frames.get(this.displayedDataTime);
frames.put(this.displayedDataTime, frame); if (frame == null) {
frame = new DisplayFrame();
frames.put(this.displayedDataTime, frame);
}
} }
// Add all the new Records // Add all the new Records
Collection<CcfpRecord> newRecords = unprocessedRecords Collection<CcfpRecord> newRecords = null;
.get(this.displayedDataTime); synchronized (unprocessedRecords) {
newRecords = unprocessedRecords.get(this.displayedDataTime);
}
for (CcfpRecord record : newRecords) { for (CcfpRecord record : newRecords) {
// If we need to draw anything for this record then keep it // If we need to draw anything for this record then keep it
if (isPaintingArea(record) || isPaintingMovement(record) if (isPaintingArea(record) || isPaintingMovement(record)
@ -259,14 +272,19 @@ public class CcfpResource extends
this.displayedDataTime = paintProps.getDataTime(); this.displayedDataTime = paintProps.getDataTime();
// First check to see if we need to process new data // First check to see if we need to process new data
Collection<CcfpRecord> unprocessed = unprocessedRecords Collection<CcfpRecord> unprocessed = null;
.get(this.displayedDataTime); synchronized (unprocessedRecords) {
unprocessed = unprocessedRecords.get(this.displayedDataTime);
}
if (unprocessed != null && unprocessed.size() > 0) { if (unprocessed != null && unprocessed.size() > 0) {
updateRecords(target, paintProps); updateRecords(target, paintProps);
} }
// Hopefully we now have some data to display, if not bail // Hopefully we now have some data to display, if not bail
DisplayFrame frame = frames.get(this.displayedDataTime); DisplayFrame frame = null;
synchronized (frames) {
frame = frames.get(this.displayedDataTime);
}
if (frame == null) { if (frame == null) {
this.displayedDataTime = null; this.displayedDataTime = null;
return; return;
@ -509,14 +527,24 @@ public class CcfpResource extends
*/ */
protected void addRecord(CcfpRecord obj) { protected void addRecord(CcfpRecord obj) {
DataTime dataTime = obj.getDataTime(); DataTime dataTime = obj.getDataTime();
Collection<CcfpRecord> records = unprocessedRecords.get(dataTime); if (resourceData.durationMatches(dataTime)) {
if (records == null) { Collection<CcfpRecord> records = null;
records = new ArrayList<CcfpRecord>(); boolean brandNew = false;
unprocessedRecords.put(dataTime, records); synchronized (unprocessedRecords) {
this.dataTimes.add(dataTime); records = unprocessedRecords.get(dataTime);
Collections.sort(this.dataTimes); if (records == null) {
records = new HashSet<CcfpRecord>();
unprocessedRecords.put(dataTime, records);
brandNew = true;
}
}
if (brandNew) {
this.dataTimes.add(dataTime);
Collections.sort(this.dataTimes);
}
records.add(obj);
} }
records.add(obj);
} }
@Override @Override
@ -677,16 +705,40 @@ public class CcfpResource extends
@Override @Override
public void project(CoordinateReferenceSystem crs) throws VizException { public void project(CoordinateReferenceSystem crs) throws VizException {
disposeFrames(); synchronized (frames) {
// add as unprocessed to make sure frames created disposeFrames();
for (DataTime time : frames.keySet()) { // add as unprocessed to make sure frames created
DisplayFrame frame = frames.get(time); for (DataTime time : frames.keySet()) {
if (frame != null) { DisplayFrame frame = frames.get(time);
List<CcfpRecord> copyList = new ArrayList<CcfpRecord>( if (frame != null) {
frame.records); List<CcfpRecord> copyList = new ArrayList<CcfpRecord>(
unprocessedRecords.put(time, copyList); frame.records);
synchronized (unprocessedRecords) {
unprocessedRecords.put(time, copyList);
}
}
} }
} }
} }
@Override
public void remove(DataTime time) {
super.remove(time);
Collection<CcfpRecord> notNeeded = null;
synchronized (unprocessedRecords) {
notNeeded = unprocessedRecords.remove(time);
}
if (notNeeded != null) {
notNeeded.clear();
}
DisplayFrame frame = null;
synchronized (frames) {
frame = frames.remove(time);
}
if (frame != null) {
frame.dispose();
}
}
} }

View file

@ -31,12 +31,10 @@ import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.time.DataTime; import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.viz.ccfp.Activator;
import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.rsc.AbstractRequestableResourceData; import com.raytheon.uf.viz.core.rsc.AbstractRequestableResourceData;
import com.raytheon.uf.viz.core.rsc.AbstractVizResource; import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
import com.raytheon.uf.viz.core.rsc.LoadProperties; import com.raytheon.uf.viz.core.rsc.LoadProperties;
import com.raytheon.uf.viz.core.status.StatusConstants;
/** /**
* *
@ -56,8 +54,9 @@ import com.raytheon.uf.viz.core.status.StatusConstants;
*/ */
@XmlAccessorType(XmlAccessType.NONE) @XmlAccessorType(XmlAccessType.NONE)
public class CcfpResourceData extends AbstractRequestableResourceData { public class CcfpResourceData extends AbstractRequestableResourceData {
private static final transient IUFStatusHandler statusHandler = UFStatus.getHandler(CcfpResourceData.class); private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(CcfpResourceData.class);
// This flag determnies if we draw lines and polygons // This flag determnies if we draw lines and polygons
@XmlAttribute @XmlAttribute
private boolean displayArea = true; private boolean displayArea = true;
@ -69,35 +68,34 @@ public class CcfpResourceData extends AbstractRequestableResourceData {
// This flag determines if we display text boxes // This flag determines if we display text boxes
@XmlAttribute @XmlAttribute
private boolean displayText = true; private boolean displayText = true;
// Filter by coverage // Filter by coverage
@XmlAttribute @XmlAttribute
private int coverageFilter = 0; private int coverageFilter = 0;
@XmlAttribute @XmlAttribute
private int validDuration = 0; private int validDuration = 0;
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (!super.equals(obj)) { if (!super.equals(obj)) {
return false; return false;
} }
if (obj instanceof CcfpResourceData == false) { if (obj instanceof CcfpResourceData == false) {
return false; return false;
} }
CcfpResourceData other = (CcfpResourceData) obj; CcfpResourceData other = (CcfpResourceData) obj;
if (other.coverageFilter != this.coverageFilter) { if (other.coverageFilter != this.coverageFilter) {
return false; return false;
} }
if (other.validDuration != this.validDuration) { if (other.validDuration != this.validDuration) {
return false; return false;
} }
if (other.displayText != this.displayText) { if (other.displayText != this.displayText) {
return false; return false;
} }
@ -109,7 +107,7 @@ public class CcfpResourceData extends AbstractRequestableResourceData {
if (other.displayMovement != this.displayMovement) { if (other.displayMovement != this.displayMovement) {
return false; return false;
} }
return true; return true;
} }
@ -122,7 +120,7 @@ public class CcfpResourceData extends AbstractRequestableResourceData {
DataTime[] originalTimes = super.getAvailableTimes(); DataTime[] originalTimes = super.getAvailableTimes();
ArrayList<DataTime> newTimes = new ArrayList<DataTime>(); ArrayList<DataTime> newTimes = new ArrayList<DataTime>();
for (DataTime time : originalTimes) { for (DataTime time : originalTimes) {
if (time.getValidPeriod().getDuration() == validDuration * 1000) { if (durationMatches(time)) {
newTimes.add(time); newTimes.add(time);
} }
} }
@ -147,6 +145,18 @@ public class CcfpResourceData extends AbstractRequestableResourceData {
return nr; return nr;
} }
/**
* Checks if a DataTime's valid period matches the duration of the resource
* data
*
* @param time
* the time to check
* @return true if the durations are equal, otherwise false
*/
protected boolean durationMatches(DataTime time) {
return time.getValidPeriod().getDuration() == validDuration * 1000;
}
public boolean isDisplayArea() { public boolean isDisplayArea() {
return displayArea; return displayArea;
} }
@ -185,6 +195,6 @@ public class CcfpResourceData extends AbstractRequestableResourceData {
public void setValidDuration(int validDuration) { public void setValidDuration(int validDuration) {
this.validDuration = validDuration; this.validDuration = validDuration;
} }
} }