Skip to content

Commit

Permalink
ZK-3729: getDesktop() sometimes returns NULL causing NPE
Browse files Browse the repository at this point in the history
  • Loading branch information
jumperchen authored and DevChu committed Sep 19, 2024
1 parent 1d27a30 commit cb75290
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 4 deletions.
15 changes: 15 additions & 0 deletions zk/src/main/java/org/zkoss/zk/ui/impl/SimpleDesktopCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.zkoss.zk.ui.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;
Expand Down Expand Up @@ -241,6 +242,20 @@ public void stop() {
}
}

public List<Desktop> getAllDesktops() {
final boolean old = _desktops.disableExpunge(true);

try {
ArrayList<Desktop> desktops = null;
synchronized (_desktops) {
desktops = new ArrayList<Desktop>(_desktops.values());
}
return desktops;
} finally {
_desktops.disableExpunge(old);
}
}

/** Holds desktops. */
private static class Cache extends CacheMap<String, Desktop> { //serializable
private AtomicBoolean _expungeDisabled = new AtomicBoolean(false);
Expand Down
23 changes: 21 additions & 2 deletions zk/src/main/java/org/zkoss/zk/ui/impl/UiEngineImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
import org.zkoss.zk.ui.sys.Attributes;
import org.zkoss.zk.ui.sys.ComponentCtrl;
import org.zkoss.zk.ui.sys.ComponentsCtrl;
import org.zkoss.zk.ui.sys.DesktopCache;
import org.zkoss.zk.ui.sys.DesktopCtrl;
import org.zkoss.zk.ui.sys.EventProcessingThread;
import org.zkoss.zk.ui.sys.ExecutionCtrl;
Expand Down Expand Up @@ -2123,8 +2124,26 @@ private static final void doDeactivate(Execution exec) {
}

final SessionCtrl sessCtrl = (SessionCtrl) desktop.getSession();
if (sessCtrl.isInvalidated())
sessCtrl.invalidateNow();

if (sessCtrl.isInvalidated()) {

// Fix ZK-3729, only invalidate if there is no working desktop in the session.
DesktopCache desktopCache = sessCtrl.getDesktopCache();
boolean hasWorkingDesktop = false;
if (desktopCache != null) {
List<Desktop> allDesktops = desktopCache.getAllDesktops();

for (Desktop d : allDesktops) {
if (d != desktop && d.getExecution() != null) {
hasWorkingDesktop = true;
break;
}
}
}

if (!hasWorkingDesktop)
sessCtrl.invalidateNow();
}
}

/** Re-activates for another execution. It is callable only for
Expand Down
12 changes: 10 additions & 2 deletions zk/src/main/java/org/zkoss/zk/ui/sys/DesktopCache.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/* DesktopCache.java
Purpose:
Description:
History:
Tue Apr 18 10:38:22 2006, Created by tomyeh
Expand All @@ -16,6 +16,8 @@
*/
package org.zkoss.zk.ui.sys;

import java.util.List;

import org.zkoss.zk.ui.ComponentNotFoundException;
import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.Session;
Expand Down Expand Up @@ -65,4 +67,10 @@ public interface DesktopCache {
* {@link DesktopCacheProvider}.
*/
public void stop();

/** Returns all the desktops in this cache.
* It is used only internally.
* @since 10.1.0
*/
public List<Desktop> getAllDesktops();
}
1 change: 1 addition & 0 deletions zkdoc/release-note
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ ZK 10.1.0
ZK-5743: clicking menuitem fires 2 onClick events in mobile browser
ZK-5594: ListboxDataLoader doGroupsDataChange finds incorrect offset, causes class cast exception
ZK-5475: select a date with time produces an invalid result under locale pt
ZK-3729: getDesktop() sometimes returns NULL causing NPE

* Upgrade Notes
+ Remove Htmls.encodeJavaScript(), Strings.encodeJavaScript(), Strings.escape() with Strings.ESCAPE_JAVASCRIPT, and replace them with OWASP Java Encoder APIs instead.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* B101_ZK_3729Composer.java
Purpose:
Description:
History:
3:36 PM 2024/9/18, Created by jumperchen
Copyright (C) 2024 Potix Corporation. All Rights Reserved.
*/
package org.zkoss.zktest.test2;

import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Sessions;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.Div;
import org.zkoss.zul.Grid;
import org.zkoss.zul.ListModelList;

/**
* @author jumperchen
*/
public class B101_ZK_3729Composer extends SelectorComposer {

@Wire private Grid grid;
private Div rootDiv;
private ListModelList model = new ListModelList();

@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
rootDiv = (Div) comp;
grid.setModel(model);
}

@Listen(Events.ON_CLICK + "=#logout")
public void logout() {
Sessions.getCurrent().invalidate();
// ((SimpleSession)Sessions.getCurrent()).invalidateNow();
}

@Listen(Events.ON_CLICK + "=#op2")
public void longOp() {
fakeOperation(3);
model.add("success");
}

static public void fakeOperation(int seconds) {
long endTime = System.currentTimeMillis() + seconds * 1000;
while (System.currentTimeMillis() < endTime) {
// Just a busy-wait. In real scenarios, this could be some meaningful computation.
}
}
}
22 changes: 22 additions & 0 deletions zktest/src/main/webapp/test2/B101-ZK-3729.zul
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>

<!--
B101-ZK-3729.zul
Purpose:
Description:
History:
2024/9/18, Created by jumperchen
Copyright (C) 2024 Potix Corporation. All Rights Reserved.
-->
<zk>
<div apply="org.zkoss.zktest.test2.B101_ZK_3729Composer">
<button id="op2" label="sync long op"/>
<button id="logout" label="logout" />
<grid id="grid"></grid>
</div>
</zk>
1 change: 1 addition & 0 deletions zktest/src/main/webapp/test2/config.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3137,6 +3137,7 @@ B90-ZK-4431.zul=A,E,Multislider
##zats##B101-ZK-5743.zul=A,E,Compressed,JS,Debug-JS,TabletUI,Mobile,onClick
##zats##B101-ZK-5594.zul=A,E,Group,ListGroup,ROD,zkmax,Exception
##zats##B101-ZK-5475.zul=A,E,Datebox,PT,Locale,Format,Constraint
##zats##B101-ZK-3729.zul=A,E,Desktop,Session,Timeout,NPE,Multithreading

##
# Features - 3.0.x version
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* B101_ZK_3729Test.java
Purpose:
Description:
History:
11:25 AM 2024/9/19, Created by jumperchen
Copyright (C) 2024 Potix Corporation. All Rights Reserved.
*/
package org.zkoss.zktest.zats.test2;

import org.junit.jupiter.api.Test;
import org.openqa.selenium.WindowType;

import org.zkoss.test.webdriver.WebDriverTestCase;

/**
* @author jumperchen
*/
public class B101_ZK_3729Test extends WebDriverTestCase {

@Test
public void test() {
connect();
driver.switchTo().newWindow(WindowType.TAB);
driver.get(getAddress() + "/test2/B101-ZK-3729.zul");
waitResponse();
Object[] windowHandles = driver.getWindowHandles().toArray();
driver.switchTo().window((String) windowHandles[0]);
click(jq("$op2"));
driver.switchTo().window((String) windowHandles[1]);
click(jq("$logout"));
driver.switchTo().window((String) windowHandles[0]);
waitResponse();
assertNoZKError();
}
}

0 comments on commit cb75290

Please sign in to comment.