Skip to content

Commit 24919d9

Browse files
committed
Fixes #108 (again). Run HeatMapUpdateTask in a separate thread to avoid
deadlock.
1 parent cb380c4 commit 24919d9

File tree

1 file changed

+87
-221
lines changed

1 file changed

+87
-221
lines changed

EnrichmentMapPlugin/src/main/java/org/baderlab/csplugins/enrichmentmap/actions/EnrichmentMapActionListener.java

Lines changed: 87 additions & 221 deletions
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,9 @@
4343

4444
package org.baderlab.csplugins.enrichmentmap.actions;
4545

46-
47-
48-
49-
import java.util.HashMap;
5046
import java.util.List;
51-
import java.util.TreeMap;
52-
53-
import javax.swing.ListSelectionModel;
54-
import javax.swing.table.TableModel;
5547

5648
import org.baderlab.csplugins.enrichmentmap.EnrichmentMapManager;
57-
import org.baderlab.csplugins.enrichmentmap.autoannotate.AutoAnnotationManager;
58-
import org.baderlab.csplugins.enrichmentmap.autoannotate.AutoAnnotationParameters;
59-
import org.baderlab.csplugins.enrichmentmap.autoannotate.model.AnnotationSet;
60-
import org.baderlab.csplugins.enrichmentmap.autoannotate.model.Cluster;
61-
import org.baderlab.csplugins.enrichmentmap.autoannotate.task.Observer;
6249
import org.baderlab.csplugins.enrichmentmap.heatmap.HeatMapParameters;
6350
import org.baderlab.csplugins.enrichmentmap.heatmap.task.UpdateHeatMapTask;
6451
import org.baderlab.csplugins.enrichmentmap.model.EnrichmentMap;
@@ -75,228 +62,107 @@
7562
import org.cytoscape.model.events.RowsSetEvent;
7663
import org.cytoscape.model.events.RowsSetListener;
7764
import org.cytoscape.util.swing.FileUtil;
78-
import org.cytoscape.view.model.CyNetworkView;
7965
import org.cytoscape.work.SynchronousTaskManager;
8066
import org.cytoscape.work.TaskIterator;
8167

8268
/**
83-
* Created by
84-
* User: risserlin
85-
* Date: Feb 2, 2009
86-
* Time: 1:25:36 PM
69+
* Created by User: risserlin Date: Feb 2, 2009 Time: 1:25:36 PM
8770
* <p>
88-
* Class listener for node and edge selections. For each enrichment map there is a separate instance of this
89-
* class specifying the enrichment map parameters, selected nodes, selected edges and heatmap panels
71+
* Class listener for node and edge selections. For each enrichment map there is
72+
* a separate instance of this class specifying the enrichment map parameters,
73+
* selected nodes, selected edges and heatmap panels
9074
*/
91-
public class EnrichmentMapActionListener implements RowsSetListener{
92-
93-
private EnrichmentMap map;
94-
private HeatMapPanel edgeOverlapPanel;
95-
private HeatMapPanel nodeOverlapPanel;
75+
public class EnrichmentMapActionListener implements RowsSetListener {
9676

97-
private List<CyNode> Nodes;
98-
private List<CyEdge> Edges;
99-
private CyApplicationManager applicationManager;
100-
private SynchronousTaskManager syncTaskManager;
101-
private final CytoPanel cytoPanelSouth;
102-
private FileUtil fileUtil;
103-
private StreamUtil streamUtil;
77+
private HeatMapPanel edgeOverlapPanel;
78+
private HeatMapPanel nodeOverlapPanel;
79+
private CyApplicationManager applicationManager;
80+
private SynchronousTaskManager syncTaskManager;
81+
private final CytoPanel cytoPanelSouth;
82+
private FileUtil fileUtil;
83+
private StreamUtil streamUtil;
10484

105-
private boolean heatMapUpdating;
106-
10785

108-
/**
109-
* Constructor for network action listener.
110-
*
111-
* @param params - enrichment map parameters associated with this actionlistener
112-
*/
113-
public EnrichmentMapActionListener(HeatMapPanel heatMapPanel_node,HeatMapPanel heatMapPanel_edge,
114-
CyApplicationManager applicationManager,CySwingApplication application,
115-
FileUtil fileUtil, StreamUtil streamUtil,SynchronousTaskManager syncTaskManager) {
116-
117-
this.applicationManager = applicationManager;
118-
this.fileUtil = fileUtil;
119-
this.streamUtil = streamUtil;
120-
this.syncTaskManager = syncTaskManager;
121-
this.edgeOverlapPanel = heatMapPanel_edge;
122-
this.nodeOverlapPanel = heatMapPanel_node;
123-
heatMapUpdating = false;
124-
125-
this.cytoPanelSouth = application.getCytoPanel(CytoPanelName.SOUTH);
86+
public EnrichmentMapActionListener(HeatMapPanel heatMapPanel_node, HeatMapPanel heatMapPanel_edge,
87+
CyApplicationManager applicationManager, CySwingApplication application, FileUtil fileUtil,
88+
StreamUtil streamUtil, SynchronousTaskManager syncTaskManager) {
12689

127-
128-
}
90+
this.applicationManager = applicationManager;
91+
this.fileUtil = fileUtil;
92+
this.streamUtil = streamUtil;
93+
this.syncTaskManager = syncTaskManager;
94+
this.edgeOverlapPanel = heatMapPanel_edge;
95+
this.nodeOverlapPanel = heatMapPanel_node;
12996

130-
public boolean isHeatMapUpdating() {
131-
return heatMapUpdating;
97+
this.cytoPanelSouth = application.getCytoPanel(CytoPanelName.SOUTH);
13298
}
13399

134100
/**
135-
* intialize the parameters needed for this instance of the action
136-
*/
137-
private boolean initialize(CyNetwork network){
138-
//get the static enrichment map manager.
139-
EnrichmentMapManager manager = EnrichmentMapManager.getInstance();
140-
this.map = manager.getMap(network.getSUID());
141-
if(map != null){
142-
if(map.getParams().isData() && map.getParams().getHmParams() == null){
143-
//create a heatmap parameters instance for this action listener
144-
HeatMapParameters hmParams = new HeatMapParameters(edgeOverlapPanel, nodeOverlapPanel);
145-
//If there are two distinct datasets intialize the theme and range for the heatmap coloring separately.
146-
if(map.getParams().isData2() && map.getDataset(EnrichmentMap.DATASET2).getExpressionSets() != null
147-
&& !map.getDataset(EnrichmentMap.DATASET1).getExpressionSets().getFilename().equalsIgnoreCase(map.getDataset(EnrichmentMap.DATASET2).getExpressionSets().getFilename()))
148-
hmParams.initColorGradients(this.map.getDataset(EnrichmentMap.DATASET1).getExpressionSets(),this.map.getDataset(EnrichmentMap.DATASET2).getExpressionSets());
149-
else
150-
hmParams.initColorGradients(this.map.getDataset(EnrichmentMap.DATASET1).getExpressionSets());
151-
//associate the newly created heatmap parameters with the current enrichment map paramters
152-
this.map.getParams().setHmParams(hmParams);
153-
}
154-
155-
this.Nodes = this.map.getParams().getSelectedNodes();
156-
this.Edges = this.map.getParams().getSelectedEdges();
157-
return true;
158-
}
159-
return false;
160-
}
161-
/**
162-
* Handle network action. This method handles edge or node selection or unselections.
163-
*
164-
* @param event
165-
*/
166-
public void handleEvent(RowsSetEvent e) {
167-
//TODO: improve performance of calculating the Union of genesets (Nodes) and intersection of overlaps (Edges)
168-
// Meanwhile we have a flag to skip the updating of the Heatmap, which can be toggled by a check-mark in the EM-Menu
169-
heatMapUpdating = true;
170-
171-
boolean override_revalidate_heatmap = EnrichmentMapManager.getInstance().isOverrideHeatmapRevalidation();
172-
173-
//get the current network
174-
CyNetwork network = this.applicationManager.getCurrentNetwork();
175-
CyNetworkView view = this.applicationManager.getCurrentNetworkView();
176-
177-
//only handle event if it is a selected node
178-
179-
if(network != null && e != null && (e.getSource() == network.getDefaultEdgeTable() || e.getSource() == network.getDefaultNodeTable())){
180-
if(initialize(network)){
181-
182-
//There is no flag to indicate that this is only an edge/node selection
183-
//After select get the nodes and the edges that were selected.
184-
if( ! override_revalidate_heatmap ) {
185-
186-
//get the edges
187-
List<CyEdge> selectedEdges = CyTableUtil.getEdgesInState(network, CyNetwork.SELECTED, true);
188-
189-
Edges.clear();
190-
Edges.addAll(selectedEdges);
191-
192-
List<CyNode> selectedNodes = CyTableUtil.getNodesInState(network, CyNetwork.SELECTED, true);
193-
194-
Nodes.clear();
195-
Nodes.addAll(selectedNodes);
196-
197-
//once we have amalgamated all the nodes and edges, launch a task to update the heatmap.
198-
UpdateHeatMapTask updateHeatmap = new UpdateHeatMapTask(map, Nodes, Edges, edgeOverlapPanel, nodeOverlapPanel, cytoPanelSouth,applicationManager);
199-
Observer observer = new Observer();
200-
syncTaskManager.execute(new TaskIterator(updateHeatmap), observer);
201-
while (!observer.isFinished()) {
202-
try {
203-
Thread.sleep(1);
204-
} catch (InterruptedException e1) {
205-
e1.printStackTrace();
206-
}
207-
}
208-
209-
210-
//if the network has been autoannotated we need to make sure the clusters have been selected
211-
//also only handle the node selection events (not edges)
212-
//TODO:need a cleaner way to find out if the currentView has an annotation
213-
if(AutoAnnotationManager.getInstance().getAnnotationPanel()!=null && !AutoAnnotationManager.getInstance().isClusterTableUpdating()
214-
&& e.getSource() == network.getDefaultNodeTable()){
215-
216-
//go through all the clusters for this network to see if any of the cluster have all of their nodes selected
217-
HashMap<CyNetworkView, AutoAnnotationParameters> annotations = AutoAnnotationManager.getInstance().getNetworkViewToAutoAnnotationParameters();
218-
if(annotations.containsKey(view)){
219-
AnnotationSet currentAnnotation = annotations.get(view).getSelectedAnnotationSet();
220-
TableModel clusterTableModel = currentAnnotation.getClusterTable().getModel();
221-
ListSelectionModel clusterListSelectionModel = currentAnnotation.getClusterTable().getSelectionModel();
222-
223-
//if there are clusters to add or to remove only do it once we have gone through all the clusters - to avoid race conditions.
224-
clusterListSelectionModel.setValueIsAdjusting(true);
225-
226-
TreeMap<Integer, Cluster> clusters = currentAnnotation.getClusterMap();
227-
//go through each cluster - figure out which ones need to be selected and
228-
//which ones need to deselected
229-
//If any nodes in a cluster are no longer selected then deselect cluster
230-
//If all nodes in a cluster are selected then select cluster (in table and annotation)
231-
for(Cluster cluster:clusters.values()){
232-
233-
boolean select = true;
234-
boolean unselectCluster = false;
235-
for (CyNode node : cluster.getNodes()) {
236-
//if any of the nodes that belong to this cluster are not in the selected set
237-
//And the cluster is current marked as selected
238-
//then unselect the cluster
239-
if (!selectedNodes.contains(node) && cluster.isSelected()) {
240-
unselectCluster = true;
241-
break;
242-
}
243-
//if any of the nodes that belong to this cluster are not in the selected set
244-
//then do not select this cluster.
245-
if (!selectedNodes.contains(node)) {
246-
select = false;
247-
break;
248-
}
249-
}
250-
251-
//one last check, if the cluster is already selected and all its nodes are
252-
//already selected then this is not a new selection event
253-
if(select == true && cluster.isSelected())
254-
select = false;
255-
256-
//Cluster has been selected
257-
//if all nodes in a cluster are selected
258-
//update the cluster table
259-
if (select) {
260-
//set flag to tell listener that it shouldn't reselect the nodes as the user manually selected them.
261-
currentAnnotation.setManualSelection(true);
262-
for (int rowIndex = 0; rowIndex < clusterTableModel.getRowCount(); rowIndex++) {
263-
if (cluster.equals(clusterTableModel.getValueAt(rowIndex, 0))) {
264-
clusterListSelectionModel.addSelectionInterval(rowIndex, rowIndex);
265-
//AutoAnnotationManager.getInstance().flushPayloadEvents();
266-
break;
267-
}
268-
}
269-
}
270-
271-
//Cluster has been unselected
272-
//update the cluster table
273-
if(unselectCluster){
274-
//set flag to tell listener that it shouldn't reselect the nodes as the user manually selected them.
275-
currentAnnotation.setManualSelection(true);
276-
for (int rowIndex = 0; rowIndex < clusterTableModel.getRowCount(); rowIndex++) {
277-
if (cluster.equals(clusterTableModel.getValueAt(rowIndex, 0))) {
278-
clusterListSelectionModel.removeSelectionInterval(rowIndex, rowIndex);
279-
//AutoAnnotationManager.getInstance().flushPayloadEvents();
280-
break;
281-
}//end of if
282-
}//end of for
283-
284-
}//end of if unselectedcluster
285-
286-
}//end of For going through all clusters
287-
288-
//if there are clusters to add or to remove only do it once we have gone through all the clusters - to avoid race conditions.
289-
clusterListSelectionModel.setValueIsAdjusting(false);
101+
* intialize the parameters needed for this instance of the action
102+
*/
103+
private EnrichmentMap getAndInitializeEnrichmentMap(CyNetwork network) {
104+
// get the static enrichment map manager.
105+
EnrichmentMapManager manager = EnrichmentMapManager.getInstance();
106+
EnrichmentMap map = manager.getMap(network.getSUID());
107+
if (map != null) {
108+
if (map.getParams().isData() && map.getParams().getHmParams() == null) {
109+
// create a heatmap parameters instance for this action listener
110+
HeatMapParameters hmParams = new HeatMapParameters(edgeOverlapPanel, nodeOverlapPanel);
111+
// If there are two distinct datasets intialize the theme and range for the heatmap coloring separately.
112+
if (map.getParams().isData2() && map.getDataset(EnrichmentMap.DATASET2).getExpressionSets() != null && !map.getDataset(EnrichmentMap.DATASET1).getExpressionSets().getFilename().equalsIgnoreCase(map.getDataset(EnrichmentMap.DATASET2).getExpressionSets().getFilename()))
113+
hmParams.initColorGradients(map.getDataset(EnrichmentMap.DATASET1).getExpressionSets(), map.getDataset(EnrichmentMap.DATASET2).getExpressionSets());
114+
else
115+
hmParams.initColorGradients(map.getDataset(EnrichmentMap.DATASET1).getExpressionSets());
116+
// associate the newly created heatmap parameters with the current enrichment map paramters
117+
map.getParams().setHmParams(hmParams);
118+
}
119+
120+
}
121+
return map;
122+
}
290123

291-
292-
}
293-
294-
}
295-
296-
}
297-
}
298-
}//end of if e.getSource check
299-
heatMapUpdating = false;
300-
}
124+
/**
125+
* Handle network action. This method handles edge or node selection or unselections.
126+
*/
127+
public void handleEvent(RowsSetEvent e) {
128+
// TODO: improve performance of calculating the Union of genesets (Nodes) and intersection of overlaps (Edges)
129+
// Meanwhile we have a flag to skip the updating of the Heatmap, which can be toggled by a check-mark in the EM-Menu
130+
boolean override_revalidate_heatmap = EnrichmentMapManager.getInstance().isOverrideHeatmapRevalidation();
131+
132+
CyNetwork network = this.applicationManager.getCurrentNetwork();
133+
134+
// only handle event if it is a selected node
135+
if (network != null && e != null && (e.getSource() == network.getDefaultEdgeTable() || e.getSource() == network.getDefaultNodeTable())) {
136+
final EnrichmentMap map = getAndInitializeEnrichmentMap(network);
137+
if (map != null) {
138+
139+
// There is no flag to indicate that this is only an edge/node selection
140+
// After select get the nodes and the edges that were selected.
141+
if (!override_revalidate_heatmap) {
142+
143+
List<CyNode> selectedNodes = CyTableUtil.getNodesInState(network, CyNetwork.SELECTED, true);
144+
List<CyEdge> selectedEdges = CyTableUtil.getEdgesInState(network, CyNetwork.SELECTED, true);
145+
146+
final List<CyNode> Nodes = map.getParams().getSelectedNodes();
147+
final List<CyEdge> Edges = map.getParams().getSelectedEdges();
148+
149+
Nodes.clear();
150+
Nodes.addAll(selectedNodes);
151+
152+
Edges.clear();
153+
Edges.addAll(selectedEdges);
154+
155+
// Once we have amalgamated all the nodes and edges, launch a task to update the heatmap.
156+
// Start the task in a separate thread to avoid Cytoscape deadlock bug (redmine issue #3370)
157+
new Thread() {
158+
public void run() {
159+
UpdateHeatMapTask updateHeatmap = new UpdateHeatMapTask(map, Nodes, Edges, edgeOverlapPanel, nodeOverlapPanel, cytoPanelSouth, applicationManager);
160+
syncTaskManager.execute(new TaskIterator(updateHeatmap));
161+
}
162+
}.start();
163+
}
164+
}
165+
} // end of if e.getSource check
166+
}
301167

302168
}

0 commit comments

Comments
 (0)