Details

    • Type: New Feature New Feature
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 2.0-Alpha3
    • Fix Version/s: None
    • Component/s: JavaScript Client
    • Labels:
      None
    • Environment:
      ICEpush, ICEfaces

      Description

      If a user has multiple browser windows open in the same Ajax Push application (such as ICEfaces auction demo) it is possible that the Ajax Push notifications will cause the browser to issue concurrent requests to the server. This is not normally possible for a user, so many server-side frameworks are not thread-safe in these conditions (most frameworks are thread-safe against concurrent requests for different users).

      In particular, JSF is not thread-safe under concurrent requests from the same user.

      To guard against this, ICEfaces notifications can be queued.

        Activity

        Ted Goddard created issue -
        Ken Fyten made changes -
        Field Original Value New Value
        Fix Version/s 2.0.0 [ 10233 ]
        Hide
        Ted Goddard added a comment -

        Push-driven updates and user-driven updates in the same window will be automatically queued by JSF, the conflict occurs between push-driven or user-driven updates in distinct windows.

        Another way to implement this is to provide a token-passing API that provides exclusivity to the caller.

        Show
        Ted Goddard added a comment - Push-driven updates and user-driven updates in the same window will be automatically queued by JSF, the conflict occurs between push-driven or user-driven updates in distinct windows. Another way to implement this is to provide a token-passing API that provides exclusivity to the caller.
        Hide
        Ted Goddard added a comment -

        Investigation into HTML5 postMessage shows that it does not help with cross-window messaging for this feature or for propagation of Ajax Push notifications. postMessage requires a browser "window" reference, but that reference can be obtained only if the window is opened via JavaScript.

        However, it appears that HTML5 storage has a listener API that may serve in place of the cookie technique we are currently using.

        Show
        Ted Goddard added a comment - Investigation into HTML5 postMessage shows that it does not help with cross-window messaging for this feature or for propagation of Ajax Push notifications. postMessage requires a browser "window" reference, but that reference can be obtained only if the window is opened via JavaScript. However, it appears that HTML5 storage has a listener API that may serve in place of the cookie technique we are currently using.
        Hide
        Ted Goddard added a comment -

        HTML5 storage listener (below) verified on Safari, Chrome, Firefox 4, and Opera. Not supported on Firefox 3.6 or IE 8. This can be used as an efficient low-latency cross-window notification mechanism on supported browsers.

        <html>
        <body>
        <div id="outputdiv">
        </div>
        <input type="button" value="ping"
        onclick="localStorage.setItem('org.icefaces.notify', (new Date().getMilliseconds()));" >
        <script>
        window.addEventListener('storage', storageListener, false);
        function storageListener(evt) {
        if (evt.key == "org.icefaces.notify")

        { document.getElementById("outputdiv").innerHTML = evt.newValue; }

        }
        </script>
        </body>
        </html>

        Show
        Ted Goddard added a comment - HTML5 storage listener (below) verified on Safari, Chrome, Firefox 4, and Opera. Not supported on Firefox 3.6 or IE 8. This can be used as an efficient low-latency cross-window notification mechanism on supported browsers. <html> <body> <div id="outputdiv"> </div> <input type="button" value="ping" onclick="localStorage.setItem('org.icefaces.notify', (new Date().getMilliseconds()));" > <script> window.addEventListener('storage', storageListener, false); function storageListener(evt) { if (evt.key == "org.icefaces.notify") { document.getElementById("outputdiv").innerHTML = evt.newValue; } } </script> </body> </html>
        Hide
        Ted Goddard added a comment - - edited

        ICEpush can be configured for queued notification (this is an optional feature;
        you may not need it if you know your server-side framework is thread-safe).

        With queued notification on (set queued = true):

        ice.push.register(pushID, callback, queued)

        If you receive a notification callback, you have exclusivity: no other pending
        notifications will be sent to queued=true push clients until you call

        ice.push.releaseNotifications()

        Also:

        ice.push.lockNotifications()

        ice.push.lockNotifications(callback)

        Note that these may be difficult to use depending on the framework. (The internals
        of this locking callback are handled for you if queued=true.)
        We cannot actually block the calling thread in JavaScript, so the way to implement
        this appears to be through a callback that is invoked when the lock is acquired.
        This can be implemented similarly to the master election mechanism for connection
        ownership, but one difference is that the notification lock is often unheld (so spin locks
        on a cookie may work).
        As an example of the difficulty in applying this for JSF, we would need to suspend the
        XMLHttpRequest triggered by client-side event processing and resume it in a callback.
        One option is to also allow the no-arg call that indicates that the caller will accept the lock
        if it can be provided immediately:

        ice.push.lockNotifications()

        This does not protect a currently active notification, but does protect the caller
        against subsequent well-behaved notifications (those using the callback).

        Show
        Ted Goddard added a comment - - edited ICEpush can be configured for queued notification (this is an optional feature; you may not need it if you know your server-side framework is thread-safe). With queued notification on (set queued = true): ice.push.register(pushID, callback, queued) If you receive a notification callback, you have exclusivity: no other pending notifications will be sent to queued=true push clients until you call ice.push.releaseNotifications() Also: ice.push.lockNotifications() ice.push.lockNotifications(callback) Note that these may be difficult to use depending on the framework. (The internals of this locking callback are handled for you if queued=true.) We cannot actually block the calling thread in JavaScript, so the way to implement this appears to be through a callback that is invoked when the lock is acquired. This can be implemented similarly to the master election mechanism for connection ownership, but one difference is that the notification lock is often unheld (so spin locks on a cookie may work). As an example of the difficulty in applying this for JSF, we would need to suspend the XMLHttpRequest triggered by client-side event processing and resume it in a callback. One option is to also allow the no-arg call that indicates that the caller will accept the lock if it can be provided immediately: ice.push.lockNotifications() This does not protect a currently active notification, but does protect the caller against subsequent well-behaved notifications (those using the callback).
        Hide
        Ted Goddard added a comment -

        It is not essential to implement an actual queue: since contention for the lock will be relatively rare, it is sufficient that any callers waiting for the lock have a equal chance of acquiring it.

        Show
        Ted Goddard added a comment - It is not essential to implement an actual queue: since contention for the lock will be relatively rare, it is sufficient that any callers waiting for the lock have a equal chance of acquiring it.
        Hide
        Ted Goddard added a comment -

        The following code attempts to analyze the threading behavior of the storage listener callback. On Safari and Firefox, the event listeners appear to be invoked in series, while on Chrome, they appear to be invoked in parallel. In all cases, the storage "set" call returns before the event listeners are invoked.

        <html>
        <body>
        <div id="localdiv">
        </div>
        <div id="outputdiv">
        </div>
        <input type="button" value="ping"
        onclick="localStorage.setItem('org.icefaces.notify',
        (new Date().getTime())); document.getElementById('localdiv').innerHTML =
        (new Date().getTime());" >
        <div id="busydiv">
        </div>
        <script>
        window.addEventListener('storage', storageListener, false);
        function storageListener(evt) {
        if (evt.key == "org.icefaces.notify") {
        var j=0,i=0;
        for (i=0;i<=50000;i++)

        { j++; document.getElementById("busydiv").innerHTML = j; }

        document.getElementById("outputdiv").innerHTML = evt.newValue + " " + ((new Date()).getTime() - evt.newValue);
        }
        }
        </script>
        </body>
        </html>

        Show
        Ted Goddard added a comment - The following code attempts to analyze the threading behavior of the storage listener callback. On Safari and Firefox, the event listeners appear to be invoked in series, while on Chrome, they appear to be invoked in parallel. In all cases, the storage "set" call returns before the event listeners are invoked. <html> <body> <div id="localdiv"> </div> <div id="outputdiv"> </div> <input type="button" value="ping" onclick="localStorage.setItem('org.icefaces.notify', (new Date().getTime())); document.getElementById('localdiv').innerHTML = (new Date().getTime());" > <div id="busydiv"> </div> <script> window.addEventListener('storage', storageListener, false); function storageListener(evt) { if (evt.key == "org.icefaces.notify") { var j=0,i=0; for (i=0;i<=50000;i++) { j++; document.getElementById("busydiv").innerHTML = j; } document.getElementById("outputdiv").innerHTML = evt.newValue + " " + ((new Date()).getTime() - evt.newValue); } } </script> </body> </html>
        Ken Fyten made changes -
        Salesforce Case []
        Fix Version/s 2.1 [ 10259 ]
        Fix Version/s 2.0.0 [ 10233 ]
        Hide
        Ted Goddard added a comment -

        The important idea is multi-window notification using persistent storage.

        Show
        Ted Goddard added a comment - The important idea is multi-window notification using persistent storage.
        Ted Goddard made changes -
        Assignee Mircea Toma [ mircea.toma ]
        Hide
        Ted Goddard added a comment -

        On the BlackBerry console, the following is seen repeatedly, likely due to ICEpush cookie polling. This is causing power consumption on the device without need as it can only display a single window at a time.

        [0.0] start JSCmdGetCookieString
        [0.0] end JSCmdGetCookieString

        Show
        Ted Goddard added a comment - On the BlackBerry console, the following is seen repeatedly, likely due to ICEpush cookie polling. This is causing power consumption on the device without need as it can only display a single window at a time. [0.0] start JSCmdGetCookieString [0.0] end JSCmdGetCookieString
        Hide
        Mircea Toma added a comment -

        The inter-window notification mechanism using HTML5 local storage was carried as work under PUSH-136 issue.

        Show
        Mircea Toma added a comment - The inter-window notification mechanism using HTML5 local storage was carried as work under PUSH-136 issue.
        Mircea Toma made changes -
        Assignee Mircea Toma [ mircea.toma ] Ted Goddard [ ted.goddard ]
        Ken Fyten made changes -
        Salesforce Case []
        Fix Version/s 2.1 [ 10259 ]
        Assignee Ted Goddard [ ted.goddard ]
        Ted Goddard made changes -
        Assignee Jack Van Ooststroom [ jack.van.ooststroom ]
        Ted Goddard made changes -
        Fix Version/s 3.4 [ 10971 ]
        Ted Goddard made changes -
        Component/s Push Library [ 10044 ]
        Component/s Push Server [ 10043 ]
        Ted Goddard made changes -
        Component/s Push Server [ 10043 ]
        Component/s Push Library [ 10044 ]
        Ted Goddard made changes -
        Assignee Jack Van Ooststroom [ jack.van.ooststroom ]
        Hide
        Ted Goddard added a comment -

        This JIRA was mistakenly edited instead of the newly created PUSH-268 JIRA.

        Show
        Ted Goddard added a comment - This JIRA was mistakenly edited instead of the newly created PUSH-268 JIRA.
        Ted Goddard made changes -
        Fix Version/s 3.4 [ 10971 ]

          People

          • Assignee:
            Unassigned
            Reporter:
            Ted Goddard
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated: