Ignore:
Timestamp:
2024-04-23T16:08:12+12:00 (8 weeks ago)
Author:
anupama
Message:

JPhind is still being run as an application, but: 1. I've now changed the Java code to have a shutdown handler for if run as a webswing applet and to have a windowClosing handler for when run as a (webswing) application. It didn't appear to need a windowClosing handler before as it doesn't have any internal threads and didn't need thread cleanup, but having a skeleton windowClosing handler is good for if a GS3 developer needs to in future add some cleanup. 2. The mostly static parameters to Phind are now moved back from webswing.config.in to pages/webswing-phind.xsl (which only sets the webswing parameter to indicate it's being run through webswing). We don't actually have an applet element (yet) for Phind webswing: it was being pushed out by the GS3 Java code service PhindPhraseBrowse.java, but that is a different URL that we have replaced with the webswing-phind url. More incremental modifications to come. Next up will be running JPhind as a webswing applet (with or without a shim applet HTML element existing on the page).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • main/trunk/greenstone3/src/java/org/greenstone/applet/phind/JPhind.java

    r38937 r38943  
    9494import org.webswing.toolkit.api.WebswingUtil;
    9595
     96import org.webswing.toolkit.api.lifecycle.WebswingShutdownListener;
     97import org.webswing.toolkit.api.lifecycle.OnBeforeShutdownEvent;
     98
    9699import javax.swing.JApplet;
    97100import javax.swing.JComponent;
     
    108111import java.awt.event.ActionEvent;
    109112import java.awt.event.ActionListener;
     113import java.awt.event.WindowAdapter;
     114import java.awt.event.WindowEvent;
    110115
    111116import java.awt.BorderLayout;
     
    136141
    137142public class JPhind extends JApplet
    138     implements ActionListener {
    139 
     143    implements ActionListener, WebswingShutdownListener {
     144
     145    int verbosity_ = 3;
     146   
    140147    // if run as webswing vs either commandline application or as applet through appletviewer
    141148    boolean isWebswing = false;
     
    264271        // HttpUtils.parseQueryString() deprecated, so hacking decode xtra key-value pairs
    265272        // https://stackoverflow.com/questions/13592236/parse-a-uri-string-into-name-value-collection?page=1&tab=scoredesc#tab-top
    266         // String.split() is preferred over Tokenizer but 2nd parameter behaves differently
    267         // than I expected.
    268         // https://docs.oracle.com/javase/6/docs/api/java/lang/String.html#split%28java.lang.String,%20int%29
    269273        if(key.equals("xtraParams")) {
    270274            value = value.replace("&", "&"); // just in case we have html entities
    271             String[] param_list = value.split("&", 0); // 0 for all occurrences
    272             for(String key_val : param_list) {         
    273             String[] paramPair = key_val.split("=", 2); // get first 2 strings, key and val
    274             //System.err.println("key_val: " + key_val);
    275             if(paramPair.length == 2) {
    276                 String xtraParamsKey = paramPair[0];
    277                 String xtraParamsVal = paramPair[1];
    278                 //System.err.println("key - val: " + xtraParamsKey + " - " + xtraParamsVal);
    279                 appParams.put(xtraParamsKey, xtraParamsVal);
    280             }
    281             }
     275            parseXtraParams(value, "=", "&", appParams);           
    282276        }
    283        
    284277        key = value = null;
    285278        }
     
    294287    /**
    295288     * Overriding (J)Applet method getParameter to first check appParams map
    296      * if Phind was run run as an application.
     289     * if Phind was run as an application.
     290     * If run as an applet, we still check the appParams first for if the param-name
     291     * exists in any xtraParams manually parsed into appParams, before finally
     292     * checking the Applet method getParameter().
    297293     * https://stackoverflow.com/questions/15905127/overridden-methods-in-javadoc
    298294    */
     
    303299    }
    304300    else {
     301        if(appParams != null) {
     302        String value = appParams.get(name);
     303        if(value != null) {
     304            return value;
     305        }
     306        }
    305307        return super.getParameter(name);
    306308    }
     
    321323    }
    322324
    323 
     325    // Given a string xtraParams of key-value pairs separatod by pairSeparators,
     326    // parses out each (key, value) and puts them into the given map, allocating it if
     327    // necessary, and returns this map.
     328    Map parseXtraParams(String xtraParams, String kvSeparator, String kvPairSeparator, Map map) {
     329   
     330    // String.split() is preferred over Tokenizer but 2nd parameter behaves differently
     331    // than I expected.
     332    // https://docs.oracle.com/javase/6/docs/api/java/lang/String.html#split%28java.lang.String,%20int%29
     333    String[] param_list = xtraParams.split(kvPairSeparator, 0);// 0 means for all occurrences
     334   
     335    if(map == null) {
     336        map = new HashMap<String,String>(param_list.length);
     337    }
     338   
     339    for(String key_val : param_list) {
     340        String[] paramPair = key_val.split(kvSeparator, 2); // get first 2 strings, key and val
     341        //System.err.println("key_val: " + key_val);
     342        if(paramPair.length == 2) {
     343        String xtraParamsKey = paramPair[0];
     344        String xtraParamsVal = paramPair[1];
     345        // Let's remove any bookending quotes from value, this is necessary for some
     346        // values when run as a webswing applet
     347        if(xtraParamsVal.startsWith("\"") && xtraParamsVal.endsWith("\"")) {
     348            xtraParamsVal = xtraParamsVal.substring(1, xtraParamsVal.length()-1);
     349        }
     350
     351        if (verbosity_ >= 4) {
     352            System.err.println("*** xtraParams key - val: " + xtraParamsKey + " - " + xtraParamsVal);
     353        }
     354        map.put(xtraParamsKey, xtraParamsVal);
     355        }
     356    }
     357
     358    return map;
     359    }
     360   
    324361    public void init() {
    325362
     
    329366    getParameters();
    330367
     368    // if running as a *webswing applet*, need to do extra work when shutdown is called
     369    // It will be triggered from a JavaScript call to webswing's kill(). By default that
     370    // generates a windowClosing event, which is only detected if we're running as a
     371    // webswing application. For a webswing applet, we add a shutdownlistener to do more
     372    // when JS calls webswing's kill(): Phind has no threads that we need to implement
     373    // stop() and destroy() (we'll call them in sequence anyway to futureproof the shutdown)
     374    // but especially, we call System.exit(0) on shutdown, which we do NOT want to do
     375    // if we're running as a regular applet instead of webswing applet.
     376    if(isWebswing && isRunAsApplet) {
     377        WebswingUtil.getWebswingApi().addShutdownListener(this);
     378    }
     379   
     380   
    331381    // Initialise the user interface
    332382    setBackground(panel_bg);
     
    445495    }
    446496
     497    // implementing WebswingShutdownListener
     498    /**
     499     * Invoked before Webswing requests application to exit.
     500     * Do not execute long operations in this listener - listener execution will be interrupted if blocking for &gt; 3 seconds and the application will exit without delay.
     501     * Connection to server is still open when this callback is triggered.
     502     * This method can delay the shutdown. Calling {@link WebswingApi#resetInactivityTimeout()} within the delay period will cancel the shutdown sequence.
     503     *
     504     * This method is not called on the event dispatch thread.
     505     *
     506     * @param event Event contains the reason of this shutdown - either triggered from Admin console's rest interface or by inactivity
     507     * @return number of seconds to delay the shutdown, returning 0 will cause shutdown without delay (even if {@link WebswingApi#resetInactivityTimeout()} has been called)
     508     */
     509    public int onBeforeShutdown(OnBeforeShutdownEvent event) {
     510    return 0; // seconds to delay before starting shutdown procedure
     511    }
     512
     513    // If you add more cleanup code here for when run as a webswing applet,
     514    // think if it should be added in the windowClosing handler in main() as well.
     515    /**
     516     * Invoked when Webswing requests swing application to exit.
     517     * This method should cause this process to exit (not necessarily in the same thread).
     518     * When this method is called, connection to server is already closed
     519     *
     520     * This method is not called on the event dispatch thread.
     521     */
     522    public void onShutdown() {
     523    // https://docs.oracle.com/javase%2F7%2Fdocs%2Fapi%2F%2F/java/applet/Applet.html#destroy()
     524    //   destroy(): "Called by the browser or applet viewer to inform this applet that
     525    //   it is being reclaimed and that it should destroy any resources that it has
     526    //   allocated. The stop method will always be called before destroy."
     527    // Running in webswing code here now, we're in the position of the browser at this point,
     528    // and must keep to the above contract.
     529    if (verbosity_ >= 3) {
     530        System.err.println("------- JPhind: WebswingShutdownListener.onShutdown() - shutting down");       
     531    }
     532    stop();
     533    destroy();
     534   
     535    // System.exit(0) is not done for regular applets, but this shutdown handler is *only*
     536    // registered if Phind is run as a *webswing applet*. Webswing running applets isn't
     537    // entirely the same as  a browser running applets, but more like a framework that
     538    // launches an applet semi like an application (perhaps in a container).
     539    // We found we could call System.exit(0) on a webswing applet here and it doesn't have
     540    // the side-effect of shutting down the webswing running it or anything, so it seems
     541    // fine to do, and we feel we *need* to do it as we'd like to clean up resources onShutdown
     542    // Note that onShutdown is a custom handler we register if we run as a webswing applet,
     543    // so that our webswing applet responds as we intend to the JavaScript kill() call that
     544    // comes in when a user navigates away from the page running the webswing applet.
     545    // Without implememnting WebswingShutdownListener, the webswing applet would not have
     546    // terminated, but still linger on. Phind is not a multi-threaded applet, so the calls to
     547    // stop() and destroy() above do not stop any internal threads launched, but the Phind
     548    // program would still have allocated memory and we'd like them deallocated when the
     549    // user navigates away.
     550    System.exit(0);
     551   
     552    }
     553   
    447554    // Search for a word
    448555    //
     
    754861    // Get the applet parameters
    755862    void getParameters() {
     863   
     864    // To get the webswing applet version of JPhind to work when
     865    // specifiying custom parameters outside the webswing.config.in file,
     866    // we have xtraParams, a string of key1::value1;;key2::value2 pairs
     867    // that we first need to extract and add to final list of applet parameters
     868    // we're working with.
     869    String xtraParams = getParameter("xtraParams");
     870    if(xtraParams != null) {
     871        // will optionally create appParams and add the key,value pairs in xtraParams into it
     872        // after splitting key::value;;k2::v2 etc
     873        appParams = parseXtraParams(xtraParams, "::", ";;", appParams);
     874    }
     875
     876    verbosity_ = parameterValue("verbosity", verbosity_);
     877   
    756878    String webswing = parameterValue("webswing", "0");
    757879    isWebswing = webswing.equals("1") ? true : false;
     
    11661288        // https://stackoverflow.com/questions/19433358/difference-between-dispose-and-exit-on-close-in-java
    11671289        // default: https://docs.oracle.com/javase/8/docs/api/javax/swing/JFrame.html#EXIT_ON_CLOSE
    1168         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // don't do EXIT_ON_CLOSE in Applets!
     1290        // don't do EXIT_ON_CLOSE in Applets. But being in main() means we're being run
     1291        // as an application.
     1292        // When the windowClosing event is received, EXIT_ON_CLOSE will call windowClosing handlers
     1293        // and then I think do a System.exit(0).
     1294        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    11691295        frame.setVisible(true);
    1170 
     1296       
     1297       
     1298        // There's no real cleanup to do now, but adding in the skeleton for application shutdown
     1299        // if there's ever any need for cleanup code. You'll then want to add cleanup code here
     1300        // iff JPhind is run as a application or as a webswing application. Then you'll want to
     1301        // add cleanup code to stop()/destroy() too which get called if running as a regular
     1302        // applet and also get called by our onShutDown() handler of WebswingShutdownListener
     1303        // for the webswing applet case.
     1304        frame.addWindowListener(new WindowAdapter() {
     1305        public void windowClosing(WindowEvent e) {
     1306            // Calling phind.showStatus() here doesn't work, maybe it's too late at this pt
     1307            // and the JFrame is already being dismantled?
     1308
     1309           
     1310            if(phind.isWebswing) {
     1311            // This call will only work if run as *webswing application* and the user
     1312            // manually clicked on the JPhind frame's window close button. Not if
     1313            // the user navigated away: at that point the webpage has already
     1314            // unloaded and its webswing listeners too, so the javascript
     1315            // can't echo this message to console:
     1316                WebswingUtil.getWebswingApi().sendActionEvent("javaToWebswingJSConsoleLog", "JPhind run as application - quitting now", null);         
     1317            }
     1318           
     1319            // Print stmts go to the terminal if run as a regular application. If run as
     1320            // webswing application/applet, then into packages/tomcat/bin/logs/webswing.log
     1321            System.err.println("\n\n*** Exitting the JPhind application...");
     1322        }
     1323        });
    11711324    }
    11721325    }
Note: See TracChangeset for help on using the changeset viewer.