Changeset 34234

Show
Ignore:
Timestamp:
01.07.2020 03:26:12 (2 weeks ago)
Author:
ak19
Message:

Bugfix I think for the deadlock issue that can occur when a GUI task on client-GLI's remote action queue results in an error attempting to produce a popup also run on the GUI thread. showMessageDialog() for error msgs now wrapped in a SwingUtilities?.invokeLater(). This does seem to have fixed the deadlock for the exact example case I encountered, which was the issue fixed in commit revision 34232.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • main/trunk/gli/src/org/greenstone/gatherer/remote/ActionQueue.java

    r34153 r34234  
    7979    } 
    8080     
    81     // We often end up with giant blotted remote build error messages when things blow up 
    82     // These messages appear in pop ups that take up the entire screen and we can't even see the OK button 
    83     // This method therefore adds a scrollPane around error messages when displaying them. 
    84     // https://alvinalexander.com/java/joptionpane-showmessagedialog-example-scrolling/ 
    85     private JScrollPane getMsgInScrollPane(String msg) { 
    86     // create a JTextArea 
    87     JTextArea textArea = new JTextArea(20, 70); 
    88     textArea.setText(msg); 
    89     textArea.setEditable(false); 
    90     // wrap a scrollpane around message 
    91     JScrollPane scrollPane = new JScrollPane(textArea); 
    92     return scrollPane; 
    93     } 
    9481     
    9582    synchronized public void addAction(RemoteGreenstoneServerAction remote_greenstone_server_action) 
     
    161148            DebugStream.printStackTrace(exception); 
    162149        } 
    163         JScrollPane scrollPane = getMsgInScrollPane(Dictionary.get("RemoteGreenstoneServer.Error", exception.getMessage())); 
    164         JOptionPane.showMessageDialog(Gatherer.g_man, scrollPane, Dictionary.get("RemoteGreenstoneServer.Error_Title"), JOptionPane.ERROR_MESSAGE); 
     150        RemoteErrorPopup.invokeLater(exception.getMessage()); 
    165151        remote_greenstone_server_action.processed_successfully = false;          
    166152        } 
     
    170156        exit = true; 
    171157        DebugStream.printStackTrace(exception); 
    172         JScrollPane scrollPane = getMsgInScrollPane(Dictionary.get("RemoteGreenstoneServer.Error",  
    173                                  "No gliserver.pl found. " + exception.getMessage())); 
    174         JOptionPane.showMessageDialog(Gatherer.g_man,  
    175                           scrollPane,  
    176                           Dictionary.get("RemoteGreenstoneServer.Error_Title"),  
    177                           JOptionPane.ERROR_MESSAGE); 
     158        RemoteErrorPopup.invokeLater("No gliserver.pl found. " + exception.getMessage()); 
    178159        remote_greenstone_server_action.processed_successfully = false; 
    179160        } 
    180161        catch (Exception exception) { 
    181162        DebugStream.printStackTrace(exception); 
    182         JScrollPane scrollPane = getMsgInScrollPane(Dictionary.get("RemoteGreenstoneServer.Error", exception.getMessage())); 
    183         JOptionPane.showMessageDialog(Gatherer.g_man, scrollPane, Dictionary.get("RemoteGreenstoneServer.Error_Title"), JOptionPane.ERROR_MESSAGE); 
     163        RemoteErrorPopup.invokeLater(exception.getMessage()); 
    184164        remote_greenstone_server_action.processed_successfully = false; 
    185165        } 
     
    208188    } 
    209189    } 
     190 
     191     
     192    // When deadlock, referred to in Kathy's commit comments as stalemate, occurs during a RemoteGS threaded 
     193    // task run on a queue, and this task is a GUI one and on the GUI thread, such as launching GEMS from the 
     194    // MetadataSetManager to create/edit a metadata set, any remote errors that then cause error dialogs to 
     195    // pop up result in a deadlock between the widgets since there's waiting going on for the first widget. 
     196    // This prevents the second widget from showing or working right, as both are on the same (GUI) thread. 
     197    // As end result, client-GLI freezes. 
     198    // An example of such an error that caused an error message to popup resulting in a GUI deadlock was 
     199    // fixed in commit http://trac.greenstone.org/changeset/34232 (client-GLI > MetadataSetManager > GEMS) 
     200    // But in theory such a GUI deadlock could happen for as yet unfixed errors. It prevents us from even 
     201    // reading the error msg in the popup and delays debugging. What we need is to show the popup when 
     202    // the GUI thread is free, i.e. SwingUtilities.invokeLater() stuff. 
     203    // Private inner class RemoteErrorPopup deals with that. Refer to: 
     204    // - https://stackoverflow.com/questions/1595744/is-joptionpane-showmessagedialog-thread-safe 
     205    //   "JOptionPane does not document that it is thread safe, so you have to use invokeLater()." 
     206    //   Also contains SwingWorker-based idea for the GUI thread clash between OpenCollDialog and 
     207    // ProgressBar during automated Greenstone GUI testing. 
     208    // - https://stackoverflow.com/questions/13863713/which-thread-to-launch-joptionpane 
     209    // - https://www.codota.com/code/java/methods/javax.swing.JOptionPane/showMessageDialog 
     210    // - https://www.programcreek.com/java-api-examples/?class=javax.swing.SwingUtilities&method=invokeLater 
     211    private static class RemoteErrorPopup implements Runnable { 
     212 
     213    /** Custom static method to make a safely threaded popup easier to call */ 
     214    public static void invokeLater(String msg) { 
     215        SwingUtilities.invokeLater(new RemoteErrorPopup(msg)); 
     216    } 
     217 
     218     
     219    private String message; 
     220     
     221    private RemoteErrorPopup(String msg) { 
     222        message = msg; 
     223    } 
     224 
     225         
     226    @Override 
     227    public void run() { 
     228         
     229        String msg = Dictionary.get("RemoteGreenstoneServer.Error", message); 
     230 
     231        // We often end up with giant bloated remote build error messages when things blow up 
     232        // These messages appear in pop ups that take up the entire screen and we can't even see the OK button 
     233        // The following therefore adds a scrollPane around error messages shown in showMessageDialog 
     234        // https://alvinalexander.com/java/joptionpane-showmessagedialog-example-scrolling/ 
     235        JTextArea textArea = new JTextArea(20, 70); 
     236        textArea.setText(msg); 
     237        textArea.setEditable(false); 
     238        // wrap a scrollpane around message 
     239        JScrollPane scrollPane = new JScrollPane(textArea);      
     240         
     241        JOptionPane.showMessageDialog(Gatherer.g_man, scrollPane, Dictionary.get("RemoteGreenstoneServer.Error_Title"), JOptionPane.ERROR_MESSAGE); 
     242    }    
     243    } 
     244     
    210245} 
     246 
     247