- Timestamp:
- 2024-04-23T16:08:12+12:00 (8 weeks ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
main/trunk/greenstone3/src/java/org/greenstone/applet/phind/JPhind.java
r38937 r38943 94 94 import org.webswing.toolkit.api.WebswingUtil; 95 95 96 import org.webswing.toolkit.api.lifecycle.WebswingShutdownListener; 97 import org.webswing.toolkit.api.lifecycle.OnBeforeShutdownEvent; 98 96 99 import javax.swing.JApplet; 97 100 import javax.swing.JComponent; … … 108 111 import java.awt.event.ActionEvent; 109 112 import java.awt.event.ActionListener; 113 import java.awt.event.WindowAdapter; 114 import java.awt.event.WindowEvent; 110 115 111 116 import java.awt.BorderLayout; … … 136 141 137 142 public class JPhind extends JApplet 138 implements ActionListener { 139 143 implements ActionListener, WebswingShutdownListener { 144 145 int verbosity_ = 3; 146 140 147 // if run as webswing vs either commandline application or as applet through appletviewer 141 148 boolean isWebswing = false; … … 264 271 // HttpUtils.parseQueryString() deprecated, so hacking decode xtra key-value pairs 265 272 // 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 differently267 // than I expected.268 // https://docs.oracle.com/javase/6/docs/api/java/lang/String.html#split%28java.lang.String,%20int%29269 273 if(key.equals("xtraParams")) { 270 274 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); 282 276 } 283 284 277 key = value = null; 285 278 } … … 294 287 /** 295 288 * 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(). 297 293 * https://stackoverflow.com/questions/15905127/overridden-methods-in-javadoc 298 294 */ … … 303 299 } 304 300 else { 301 if(appParams != null) { 302 String value = appParams.get(name); 303 if(value != null) { 304 return value; 305 } 306 } 305 307 return super.getParameter(name); 306 308 } … … 321 323 } 322 324 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 324 361 public void init() { 325 362 … … 329 366 getParameters(); 330 367 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 331 381 // Initialise the user interface 332 382 setBackground(panel_bg); … … 445 495 } 446 496 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 > 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 447 554 // Search for a word 448 555 // … … 754 861 // Get the applet parameters 755 862 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 756 878 String webswing = parameterValue("webswing", "0"); 757 879 isWebswing = webswing.equals("1") ? true : false; … … 1166 1288 // https://stackoverflow.com/questions/19433358/difference-between-dispose-and-exit-on-close-in-java 1167 1289 // 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); 1169 1295 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 }); 1171 1324 } 1172 1325 }
Note:
See TracChangeset
for help on using the changeset viewer.