diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/internal/AbstractParmManager.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/internal/AbstractParmManager.java index 57cd43a73f..fe06f8d742 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/internal/AbstractParmManager.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/internal/AbstractParmManager.java @@ -89,6 +89,7 @@ import com.raytheon.viz.gfe.core.parm.vcparm.VCModule; * dispose method. * 02/23/2012 #346 dgilling Ensure all Parms are disposed when calling * dispose method. + * 03/01/2012 #346 dgilling Use identity-based ListenerLists. * * * @@ -246,12 +247,14 @@ public abstract class AbstractParmManager implements IParmManager { protected AbstractParmManager(final DataManager dataManager) { this.dataManager = dataManager; this.parms = new RWLArrayList(); - this.displayedParmListListeners = new ListenerList(); - this.parmListChangedListeners = new ListenerList(); - this.systemTimeRangeChangedListeners = new ListenerList(); - this.availableSourcesListeners = new ListenerList(); - this.newModelListeners = new ListenerList(); - this.parmIdChangedListeners = new ListenerList(); + this.displayedParmListListeners = new ListenerList( + ListenerList.IDENTITY); + this.parmListChangedListeners = new ListenerList(ListenerList.IDENTITY); + this.systemTimeRangeChangedListeners = new ListenerList( + ListenerList.IDENTITY); + this.availableSourcesListeners = new ListenerList(ListenerList.IDENTITY); + this.newModelListeners = new ListenerList(ListenerList.IDENTITY); + this.parmIdChangedListeners = new ListenerList(ListenerList.IDENTITY); // Get virtual parm definitions vcModules = initVirtualCalcParmDefinitions(); diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/internal/NotificationRouter.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/internal/NotificationRouter.java index b623a3397f..049c5e6f20 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/internal/NotificationRouter.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/internal/NotificationRouter.java @@ -43,10 +43,11 @@ import com.raytheon.viz.gfe.Activator; * *
  * SOFTWARE HISTORY
- * Date			Ticket#		Engineer	Description
- * ------------	----------	-----------	--------------------------
- * Jun 11, 2008				chammack	Initial creation
- * Sep 3, 2008  1448        chammack    Implement refactored interface
+ * Date         Ticket#     Engineer    Description
+ * ------------ ----------  ----------- --------------------------
+ * Jun 11, 2008             chammack    Initial creation
+ * Sep 03, 2008  1448       chammack    Implement refactored interface
+ * Mar 01, 2012  #346       dgilling    Use identity-based ListenerLists.
  * 
* * @author chammack @@ -68,7 +69,7 @@ public class NotificationRouter implements INotificationObserver { */ public NotificationRouter(String siteID) { this.siteID = siteID; - this.observers = new ListenerList(); + this.observers = new ListenerList(ListenerList.IDENTITY); this.observers .add(new AbstractGFENotificationObserver( UserMessageNotification.class) { @@ -178,6 +179,7 @@ public class NotificationRouter implements INotificationObserver { /** * Notification that a message has arrived */ + @Override @SuppressWarnings("unchecked") public void notificationArrived(NotificationMessage[] messages) { // If DataManager is not initialized yet, do not start listening diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/DbParm.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/DbParm.java index b36969bc13..cb820f0e0f 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/DbParm.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/DbParm.java @@ -71,6 +71,7 @@ import com.raytheon.viz.gfe.core.griddata.IGridData; * 01/29/08 #1271 njensen Rewrote populateGridFromData() * to use IFPClient * 02/23/12 #346 dgilling Implement a dispose method. + * 03/01/12 #346 dgilling Re-order dispose method. * * * @@ -122,8 +123,8 @@ public class DbParm extends Parm { */ @Override public void dispose() { - super.dispose(); looseLocks(); + super.dispose(); } // -- private diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/Parm.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/Parm.java index 78a52ded63..32c5bd5c84 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/Parm.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/Parm.java @@ -173,6 +173,9 @@ import com.vividsolutions.jts.geom.Coordinate; * 06/08/2009 #2159 rjpeter Fixed undo. * 02/23/2012 #346 dgilling Implement a dispose method to mimic * AWIPS1 use of C++ destructor. + * 03/02/2012 #346 dgilling Create a disposed flag to help ensure + * no interaction with Parms after dispose + * is called. * * * @author chammack @@ -215,6 +218,8 @@ public abstract class Parm implements Comparable { protected String officeType; + protected boolean disposed; + /** * The create from scratch mode */ @@ -348,9 +353,15 @@ public abstract class Parm implements Comparable { if (this.officeType == null) { this.officeType = dataManager.getOfficeType(); } + + this.disposed = false; } public void dispose() { + synchronized (this) { + this.disposed = true; + } + if (isModified()) { statusHandler.warn("Destroying parm " + getParmID().toString() + " with modified data."); diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/ParmListeners.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/ParmListeners.java index f5eebb9ced..4b4fa0464e 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/ParmListeners.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/ParmListeners.java @@ -50,12 +50,13 @@ import com.raytheon.viz.gfe.core.wxvalue.WxValue; * *
  * SOFTWARE HISTORY
- * Date			Ticket#		Engineer	Description
- * ------------	----------	-----------	--------------------------
- * Jun 13, 2008				chammack	Initial creation
+ * Date         Ticket#     Engineer    Description
+ * ------------ ----------  ----------- --------------------------
+ * Jun 13, 2008             chammack    Initial creation
  * Sep 01, 2009  #2788      randerso    Changed listener lists to sets to prevent
  *                                      multiple registration
  * Feb 23, 2012  #346       dgilling    Implement clearParmListeners.
+ * Mar 01, 2012  #346       dgilling    Use identity-based ListenerLists.
  * 
  * 
* @@ -88,16 +89,23 @@ public class ParmListeners { private final JobPool notificationPool; protected ParmListeners(JobPool pool) { - this.gridChangedListeners = new ListenerList(); - this.parmInventoryChangedListeners = new ListenerList(); - this.parmIDChangedListeners = new ListenerList(); - this.selectionTimeRangeChangedListeners = new ListenerList(); - this.parameterSelectionChangedListeners = new ListenerList(); - this.combineModeChangedListeners = new ListenerList(); - this.vectorModeChangedListeners = new ListenerList(); - this.pickupValueChangedListeners = new ListenerList(); - this.colorTableModifiedListeners = new ListenerList(); - this.lockTableChangedListeners = new ListenerList(); + this.gridChangedListeners = new ListenerList(ListenerList.IDENTITY); + this.parmInventoryChangedListeners = new ListenerList( + ListenerList.IDENTITY); + this.parmIDChangedListeners = new ListenerList(ListenerList.IDENTITY); + this.selectionTimeRangeChangedListeners = new ListenerList( + ListenerList.IDENTITY); + this.parameterSelectionChangedListeners = new ListenerList( + ListenerList.IDENTITY); + this.combineModeChangedListeners = new ListenerList( + ListenerList.IDENTITY); + this.vectorModeChangedListeners = new ListenerList( + ListenerList.IDENTITY); + this.pickupValueChangedListeners = new ListenerList( + ListenerList.IDENTITY); + this.colorTableModifiedListeners = new ListenerList( + ListenerList.IDENTITY); + this.lockTableChangedListeners = new ListenerList(ListenerList.IDENTITY); this.notificationPool = pool; } diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/VCParm.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/VCParm.java index 437656701e..6a826d7206 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/VCParm.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/core/parm/VCParm.java @@ -64,6 +64,9 @@ import com.raytheon.viz.gfe.core.parm.vcparm.VCModule.VCInventory; * data. Also, remove overridden * finalize function. * Feb 23, 2012 #346 dgilling Implement a dispose method. + * Mar 02, 2012 #346 dgilling Use Parm's new disposed flag to + * prevent leaks through + * ListenerLists. * * * @@ -138,6 +141,12 @@ public class VCParm extends VParm implements IParmListChangedListener, */ @Override public void gridDataChanged(final ParmID parmId, final TimeRange validTime) { + synchronized (this) { + if (disposed) { + return; + } + } + // statusHandler.handle(Priority.DEBUG, "gridDataChanged for: " + parmId // + " " + validTime); @@ -167,7 +176,6 @@ public class VCParm extends VParm implements IParmListChangedListener, } } } - } /* @@ -182,13 +190,22 @@ public class VCParm extends VParm implements IParmListChangedListener, @Override public void parmListChanged(final Parm[] parms, Parm[] deletions, Parm[] additions) { - // statusHandler.handle(Priority.DEBUG, - // "ParmListChangedMsg received: "); - System.out.println("ParmListChangedMsg received: " - + getParmID().toString()); - registerParmClients(parms, true); + // forcing access to the disposed variable and subsequent + // registration/unregistation of listeners through this synchronized + // block seems to prevent VCParm objects being leaked through outdated + // listener list copies + synchronized (this) { + if (disposed) { + return; + } + // statusHandler.handle(Priority.DEBUG, + // "ParmListChangedMsg received: "); + // System.out.println("ParmListChangedMsg received: " + // + getParmID().toString()); + registerParmClients(parms, true); + } } /* @@ -208,8 +225,13 @@ public class VCParm extends VParm implements IParmListChangedListener, // approach. // statusHandler.debug("ParmInventoryChanged notification for: " // + getParmID().toString()); - System.out.println("ParmInventoryChanged notification for: " - + getParmID().toString()); + // System.out.println("ParmInventoryChanged notification for: " + // + getParmID().toString()); + synchronized (this) { + if (disposed) { + return; + } + } recalcInventory(true); } @@ -467,9 +489,6 @@ public class VCParm extends VParm implements IParmListChangedListener, } private void registerPC(Parm parm) { - System.out.println(getParmID().toString() + " is registering " - + parm.toString()); - parm.parmListeners.addGridChangedListener(this); parm.parmListeners.addParmInventoryChangedListener(this); @@ -482,9 +501,6 @@ public class VCParm extends VParm implements IParmListChangedListener, } private void unregisterPC(Parm parm) { - System.out.println(getParmID().toString() + " is unregistering " - + parm.toString()); - parm.parmListeners.removeGridChangedListener(this); parm.parmListeners.removeParmInventoryChangedListener(this); diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/smarttool/script/SmartToolUIController.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/smarttool/script/SmartToolUIController.java index 82d4ab5eea..54bb05360e 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/smarttool/script/SmartToolUIController.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/smarttool/script/SmartToolUIController.java @@ -42,6 +42,7 @@ import com.raytheon.viz.gfe.core.msgs.ISmartToolInventoryChanged; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Jan 19, 2010 njensen Initial creation + * Mar 01, 2012 #346 dgilling Use identity-based ListenerLists. * * * @@ -58,7 +59,7 @@ public class SmartToolUIController extends SmartToolController { throws JepException { super(filePath, anIncludePath, classLoader, dataManager); - invChangedListeners = new ListenerList(); + invChangedListeners = new ListenerList(ListenerList.IDENTITY); } /** diff --git a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/tasks/TaskScheduler.java b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/tasks/TaskScheduler.java index 8a4119f001..62e01c3ebb 100644 --- a/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/tasks/TaskScheduler.java +++ b/cave/com.raytheon.viz.gfe/src/com/raytheon/viz/gfe/tasks/TaskScheduler.java @@ -46,7 +46,8 @@ import com.raytheon.viz.gfe.tasks.AbstractGfeTask.TaskStatus; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * Apr 7, 2011 randerso Initial creation + * Apr 07, 2011 randerso Initial creation + * Mar 03, 2012 #346 dgilling Use identity-based ListenerLists. * * * @@ -70,7 +71,7 @@ public class TaskScheduler extends Job { protected TaskScheduler() { super("Task Manager Job"); - listeners = new ListenerList(); + listeners = new ListenerList(ListenerList.IDENTITY); PythonPreferenceStore prefs = Activator.getDefault() .getPreferenceStore();