Search code examples
jsf-2seam3deltaspike

Alternative to Deltaspike Multi-Window Handling in Seam 3 Applikation


I have problems with the Multi-Window Handling in my appliacation. I currently using Conversation Scope to enable multi window / tab handling but in case the user opens a link (button) in a new tab the conversation is shared between the old and new tab.

Apache Deltaspike has a solution for that (http://deltaspike.apache.org/documentation/#_module_overview) but I already using Seam 3 (and JSF 2.1) and don't want to migrate to Deltaspike.

So I'm searching for an alternative solution without Deltaspike or is it possible to use Deltaspike AND Seam 3?


Solution

  • I build a solution with p:remoteCommand and this answer: In javascript, how can I uniquely identify one browser window from another which are under the same cookiedbased sessionId

    I added this JS to my template which creates a unique id for each browswer tab an stores it in the window.name. Then it calls a p:remoteCommand to check the guid:

    $(window).load(function() {
        // ----------------------
        var GUID = function() {
            // ------------------
            var S4 = function() {
                return (Math.floor(Math.random() * 0x10000 /* 65536 */
                ).toString(16));
            };
            return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
        };
    
        if (!window.name.match(/^GUID-/)) {
            window.name = "GUID-" + GUID();
        }
    
        if ($('#guid_form\\:server_guid').text().length == 0 || 
                $('#guid_form\\:server_guid').text() != window.name) {
            checkGuid([{name:'guid', value:window.name}]);
        }
    })
    

    Added a Primefaces remoteCommand to my template which is called by the script above.

    <h:form id="guid_form">
        <h:outputText value="#{checkTabAction.guid}" id="server_guid"/>
        <p:remoteCommand name="checkGuid" actionListener="#{checkTabAction.checkGuid}" process="@this" partialSubmit="true" />
    </h:form>
    

    And added a check action which validateds the current browser tab / window by comparing the guid's:

    @ConversationScoped
    @Named(value = "checkTabAction")
    public class CheckTabAction implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        @Inject
        private Logger log;
    
        private String guid = null;
    
        public void checkGuid() {
            Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
            String guid = params.get("guid").toString();
    
            if (this.guid == null) {
                this.guid = guid;
            }
    
            if (!StringUtils.equals(this.guid, guid)) {
                log.info("New tab detected!");
                throw new NonexistentConversationException("New tab detected!");
            }
        }
    
        public String getGuid() {
            return guid;
        }
    
    }