You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by st...@apache.org on 2013/04/21 21:46:17 UTC

[3/3] git commit: DELTASPIKE-289 migrate windowhandler from CODI

DELTASPIKE-289 migrate windowhandler from CODI


Project: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/commit/45770596
Tree: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/tree/45770596
Diff: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/diff/45770596

Branch: refs/heads/master
Commit: 45770596d64be289e202339bbc02ebb22aed3758
Parents: 30661b0
Author: Mark Struberg <st...@apache.org>
Authored: Sun Apr 21 20:56:15 2013 +0200
Committer: Mark Struberg <st...@apache.org>
Committed: Sun Apr 21 20:56:15 2013 +0200

----------------------------------------------------------------------
 .../core/impl/scope/window/WindowBeanHolder.java   |    7 +-
 deltaspike/modules/jsf/impl/pom.xml                |    4 +
 .../request/DeltaSpikeLifecycleWrapper.java        |   30 ++-
 .../jsf/impl/scope/window/DefaultClientWindow.java |  165 +++++++++++++-
 .../META-INF/resources/js/windowhandler.js         |  180 +++++++++++++++
 .../src/main/resources/static/windowhandler.html   |  170 ++++++++++++++
 6 files changed, 545 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/45770596/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java
index b4acc46..429fa20 100644
--- a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java
@@ -41,7 +41,7 @@ public class WindowBeanHolder implements Serializable
      * value: the {@link ContextualStorage} which holds all the
      * {@link javax.enterprise.inject.spi.Bean}s.
      */
-    private volatile Map<String, ContextualStorage> storageMap = new ConcurrentHashMap<String, ContextualStorage>();
+    private Map<String, ContextualStorage> storageMap = new ConcurrentHashMap<String, ContextualStorage>();
 
     /**
      * This method will return the ContextualStorage or create a new one
@@ -67,6 +67,11 @@ public class WindowBeanHolder implements Serializable
         return contextualStorage;
     }
 
+    public Map<String, ContextualStorage> getStorageMap()
+    {
+        return storageMap;
+    }
+
     /**
      *
      * This method will replace the storageMap and with

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/45770596/deltaspike/modules/jsf/impl/pom.xml
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/pom.xml b/deltaspike/modules/jsf/impl/pom.xml
index c71899f..ee9947c 100644
--- a/deltaspike/modules/jsf/impl/pom.xml
+++ b/deltaspike/modules/jsf/impl/pom.xml
@@ -65,6 +65,10 @@
             <version>1.0</version>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-servlet_3.0_spec</artifactId>
+        </dependency>
 
         <!-- we use Arquillian Warp to test our JSF apps -->
         <dependency>

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/45770596/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java
index 9d4808d..0f91b33 100644
--- a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java
@@ -19,7 +19,9 @@
 package org.apache.deltaspike.jsf.impl.listener.request;
 
 import org.apache.deltaspike.core.api.provider.BeanProvider;
+import org.apache.deltaspike.core.spi.scope.window.WindowContext;
 import org.apache.deltaspike.core.util.ClassDeactivationUtils;
+import org.apache.deltaspike.jsf.spi.scope.window.ClientWindow;
 
 import javax.faces.context.FacesContext;
 import javax.faces.event.PhaseListener;
@@ -31,6 +33,9 @@ class DeltaSpikeLifecycleWrapper extends Lifecycle
 
     private BeforeAfterJsfRequestBroadcaster beforeAfterJsfRequestBroadcaster;
 
+    private ClientWindow clientWindow;
+    private WindowContext windowContext;
+
     private volatile Boolean initialized;
 
     DeltaSpikeLifecycleWrapper(Lifecycle wrapped)
@@ -53,13 +58,19 @@ class DeltaSpikeLifecycleWrapper extends Lifecycle
     @Override
     public void execute(FacesContext facesContext)
     {
+        lazyInit();
+
         //TODO broadcastApplicationStartupBroadcaster();
         broadcastBeforeFacesRequestEvent(facesContext);
 
-        //X TODO add ClientWindow handling
-        this.wrapped.execute(facesContext);
-
+        // ClientWindow handling
+        String windowId = clientWindow.getWindowId(facesContext);
+        if (windowId != null)
+        {
+            windowContext.activateWindow(windowId);
+        }
 
+        this.wrapped.execute(facesContext);
     }
 
     @Override
@@ -85,7 +96,6 @@ class DeltaSpikeLifecycleWrapper extends Lifecycle
 
     private void broadcastBeforeFacesRequestEvent(FacesContext facesContext)
     {
-        lazyInit();
         if (this.beforeAfterJsfRequestBroadcaster != null)
         {
             this.beforeAfterJsfRequestBroadcaster.broadcastBeforeJsfRequestEvent(facesContext);
@@ -103,15 +113,21 @@ class DeltaSpikeLifecycleWrapper extends Lifecycle
     private synchronized void init()
     {
         // switch into paranoia mode
-        if (this.initialized == null)
+        if (initialized == null)
         {
             if (ClassDeactivationUtils.isActivated(BeforeAfterJsfRequestBroadcaster.class))
             {
-                this.beforeAfterJsfRequestBroadcaster =
+                beforeAfterJsfRequestBroadcaster =
                         BeanProvider.getContextualReference(BeforeAfterJsfRequestBroadcaster.class, true);
+
+                clientWindow =
+                        BeanProvider.getContextualReference(ClientWindow.class, true);
+
+                windowContext =
+                        BeanProvider.getContextualReference(WindowContext.class, true);
             }
 
-            this.initialized = true;
+            initialized = true;
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/45770596/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/DefaultClientWindow.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/DefaultClientWindow.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/DefaultClientWindow.java
index 4ab6d37..3ea9478 100644
--- a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/DefaultClientWindow.java
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/DefaultClientWindow.java
@@ -19,13 +19,20 @@
 package org.apache.deltaspike.jsf.impl.scope.window;
 
 import javax.enterprise.context.ApplicationScoped;
+import javax.faces.FacesException;
 import javax.faces.component.UIViewRoot;
+import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
 import javax.inject.Inject;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
 
+import java.io.IOException;
+import java.io.OutputStream;
 import java.util.logging.Logger;
 
 import org.apache.deltaspike.core.spi.scope.window.WindowContext;
+import org.apache.deltaspike.jsf.impl.util.JsfUtils;
 import org.apache.deltaspike.jsf.spi.scope.window.ClientWindow;
 import org.apache.deltaspike.jsf.spi.scope.window.ClientWindowConfig;
 
@@ -46,6 +53,24 @@ public class DefaultClientWindow implements ClientWindow
 {
     private static final Logger logger = Logger.getLogger(DefaultClientWindow.class.getName());
 
+    private static final String WINDOW_ID_COOKIE_PREFIX = "dsWindowId-";
+    private static final String DELTASPIKE_REQUEST_TOKEN = "dsRid";
+
+    private static final String UNINITIALIZED_WINDOW_ID_VALUE = "uninitializedWindowId";
+    private static final String WINDOW_ID_REPLACE_PATTERN = "$$windowIdValue$$";
+    private static final String NOSCRIPT_URL_REPLACE_PATTERN = "$$noscriptUrl$$";
+
+    /**
+     * Use this parameter to force a 'direct' request from the clients without any windowId detection
+     * We keep this name for backward compat with CODI.
+     */
+    private static final String NOSCRIPT_PARAMETER = "mfDirect";
+
+    /**
+     * This windowId will be used for all requests with disabled windowId feature
+     */
+    private static final String DEFAULT_WINDOW_ID = "default";
+
 
     @Inject
     private ClientWindowConfig clientWindowConfig;
@@ -59,16 +84,36 @@ public class DefaultClientWindow implements ClientWindow
     {
         if (ClientWindowRenderMode.NONE.equals(clientWindowConfig.getClientWindowRenderMode(facesContext)))
         {
-            return null;
+            // if this request should not get any window detection then we are done
+            return DEFAULT_WINDOW_ID;
         }
 
-        String windowId = null;
-
         if (facesContext.isPostback())
         {
+            // for POST we read the windowId from the WindowIdHolderComponent in our ViewRoot
             return getPostBackWindowId(facesContext);
         }
 
+        ExternalContext externalContext = facesContext.getExternalContext();
+
+        // and now for the GET request stuff
+        if (isNoscriptRequest(externalContext))
+        {
+            // the client has JavaScript disabled
+            clientWindowConfig.setJavaScriptEnabled(false);
+
+            return DEFAULT_WINDOW_ID;
+        }
+
+        String windowId = getVerifiedWindowIdFromCookie(externalContext);
+        if (windowId == null)
+        {
+            // GET request without windowId - send windowhandlerfilter.html to get the windowId
+            sendWindowHandlerHtml(externalContext, null);
+            facesContext.responseComplete();
+        }
+
+        // we have a valid windowId - set it and continue with the request
         return windowId;
     }
 
@@ -93,4 +138,118 @@ public class DefaultClientWindow implements ClientWindow
     }
 
 
+    private boolean isNoscriptRequest(ExternalContext externalContext)
+    {
+        String noscript = externalContext.getRequestParameterMap().get(NOSCRIPT_PARAMETER);
+
+        return (noscript != null && "true".equals(noscript));
+    }
+
+
+    private void sendWindowHandlerHtml(ExternalContext externalContext, String windowId)
+    {
+        HttpServletResponse httpResponse = (HttpServletResponse) externalContext.getResponse();
+
+        try
+        {
+            httpResponse.setStatus(HttpServletResponse.SC_OK);
+            httpResponse.setContentType("text/html");
+
+            String windowHandlerHtml = clientWindowConfig.getClientWindowHtml();
+
+            if (windowId == null)
+            {
+                windowId = UNINITIALIZED_WINDOW_ID_VALUE;
+            }
+
+            // set the windowId value in the javascript code
+            windowHandlerHtml = windowHandlerHtml.replace(WINDOW_ID_REPLACE_PATTERN, windowId);
+
+            // set the noscript-URL for users with no JavaScript
+            windowHandlerHtml =
+                    windowHandlerHtml.replace(NOSCRIPT_URL_REPLACE_PATTERN, getNoscriptUrl(externalContext));
+
+            OutputStream os = httpResponse.getOutputStream();
+            try
+            {
+                os.write(windowHandlerHtml.getBytes());
+            }
+            finally
+            {
+                os.close();
+            }
+        }
+        catch (IOException ioe)
+        {
+            throw new FacesException(ioe);
+        }
+    }
+
+    private String getNoscriptUrl(ExternalContext externalContext)
+    {
+        String url = externalContext.getRequestPathInfo();
+        if (url == null)
+        {
+            url = "";
+        }
+
+        // only use the very last part of the url
+        int lastSlash = url.lastIndexOf('/');
+        if (lastSlash != -1)
+        {
+            url = url.substring(lastSlash + 1);
+        }
+
+        // add request parameter
+        url = JsfUtils.addPageParameters(externalContext, url, true);
+
+        // add noscript parameter
+        if (url.contains("?"))
+        {
+            url = url + "&";
+        }
+        else
+        {
+            url = url + "?";
+        }
+        url = url + NOSCRIPT_PARAMETER + "=true";
+
+        // NOTE that the url could contain data for an XSS attack
+        // like e.g. ?"></a><a href%3D"http://hacker.org/attack.html?a
+        // DO NOT REMOVE THE FOLLOWING LINES!
+        url = url.replace("\"", "");
+        url = url.replace("\'", "");
+
+        return url;
+    }
+
+    private String getVerifiedWindowIdFromCookie(ExternalContext externalContext)
+    {
+        String cookieName = WINDOW_ID_COOKIE_PREFIX + getRequestToken(externalContext);
+        Cookie cookie = (Cookie) externalContext.getRequestCookieMap().get(cookieName);
+
+        if (cookie != null)
+        {
+            // manually blast the cookie away, otherwise it pollutes the
+            // cookie storage in some browsers. E.g. Firefox doesn't
+            // cleanup properly, even if the max-age is reached.
+            cookie.setMaxAge(0);
+
+            return cookie.getValue();
+        }
+
+        return null;
+    }
+
+    private String getRequestToken(ExternalContext externalContext)
+    {
+        String requestToken = externalContext.getRequestParameterMap().get(DELTASPIKE_REQUEST_TOKEN);
+        if (requestToken != null)
+        {
+            return requestToken;
+        }
+
+        return "";
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/45770596/deltaspike/modules/jsf/impl/src/main/resources/META-INF/resources/js/windowhandler.js
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/resources/META-INF/resources/js/windowhandler.js b/deltaspike/modules/jsf/impl/src/main/resources/META-INF/resources/js/windowhandler.js
new file mode 100644
index 0000000..b563b31
--- /dev/null
+++ b/deltaspike/modules/jsf/impl/src/main/resources/META-INF/resources/js/windowhandler.js
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+(function() {
+//wrapping so that all internal functions are privately scoped
+function isHtml5() {
+    try {
+        return !!localStorage.getItem;
+    } catch(e) {
+        return false;
+    }
+}
+
+// some browsers don't understand JSON - guess which one ... :(
+function stringify(someArray) {
+    if (JSON) {
+        return JSON.stringify(someArray);
+    }
+    return someArray.join("|||");
+}
+
+// store the current body in the html5 localstorage
+function storeWindowTree() {
+    // first we store all CSS we also need on the intermediate page
+    var headNodes = document.getElementsByTagName("head")[0].childNodes;
+    var oldSS = new Array();
+    var j = 0;
+    for (var i = 0; i < headNodes.length; i++) {
+        var tagName = headNodes[i].tagName;
+        if (tagName && equalsIgnoreCase(tagName, "link") &&
+                equalsIgnoreCase(headNodes[i].getAttribute("type"), "text/css")) {
+
+            // sort out media="print" and stuff
+            var media = headNodes[i].getAttribute("media");
+            if (!media || equalsIgnoreCase(media, "all") || equalsIgnoreCase(media, 'screen')) {
+                oldSS[j++] = headNodes[i].getAttribute("href");
+            }
+        }
+    }
+    localStorage.setItem(window.name + '_css', stringify(oldSS));
+    var body = document.getElementsByTagName("body")[0];
+    localStorage.setItem(window.name + '_body', body.innerHTML);
+    //X TODO: store ALL attributes of the body tag
+    localStorage.setItem(window.name + '_bodyAttrs', body.getAttribute("class"));
+    return true;
+}
+
+function equalsIgnoreCase(source, destination) {
+    //either both are not set or null
+    if (!source && !destination) {
+        return true;
+    }
+    //source or dest is set while the other is not
+    if (!source || !destination) return false;
+
+    //in any other case we do a strong string comparison
+    return source.toLowerCase() === destination.toLowerCase();
+}
+
+/** This method will be called onWindowLoad and after AJAX success */
+function applyOnClick() {
+    var links = document.getElementsByTagName("a");
+    for (var i = 0; i < links.length; i++) {
+        if (!links[i].onclick) {
+            links[i].onclick = function() {storeWindowTree(); return true;};
+        } else {
+            // prevent double decoration
+            if (!("" + links[i].onclick).match(".*storeWindowTree().*")) {
+                //the function wrapper is important otherwise the
+                //last onclick handler would be assigned to oldonclick
+                (function storeEvent() {
+                    var oldonclick = links[i].onclick;
+                    links[i].onclick = function(evt) {
+                        //ie handling added
+                        evt = evt || window.event;
+
+                        return storeWindowTree() && oldonclick(evt);
+                    };
+                })();
+            }
+        }
+    }
+}
+
+function getUrlParameter(name) {
+    var url = window.location.href;
+    var vars = url.split(/&|\?/g);
+    for (var i=0; vars != null && i < vars.length; i++) {
+        var pair = vars[i].split("=");
+        if (pair[0]==name) {
+            return pair[1];
+        }
+    }
+    return null;
+}
+function setUrlParam(baseUrl, paramName, paramValue) {
+    var query = baseUrl;
+    var vars = query.split(/&|\?/g);
+    var newQuery = "";
+    var iParam = 0;
+    var paramFound = false;
+    for (var i=0; vars != null && i < vars.length; i++) {
+        var pair = vars[i].split("=");
+        if (pair.length == 1) {
+            newQuery = pair[0];
+        } else {
+            if (pair[0] != paramName) {
+                var amp = iParam++ > 0 ? "&" : "?";
+                newQuery =  newQuery + amp + pair[0] + "=" + pair[1];
+            } else {
+                paramFound = true;
+                if (paramValue) {
+                    var amp = iParam++ > 0 ? "&" : "?";
+                    newQuery =  newQuery + amp + paramName + "=" + paramValue;
+                }
+            }
+        }
+    }
+    if (!paramFound && paramValue) {
+        var amp = iParam++ > 0 ? "&" : "?";
+        newQuery =  newQuery + amp + paramName + "=" + paramValue;
+    }
+    return newQuery;
+}
+// this method runs to ensure that windowIds get checked even if no windowhandler.html is used
+function assertWindowId() {
+    if (!window.name || window.name.length < 1) {
+        url = setUrlParam(window.location.href, 'windowId', null);
+        window.name = 'tempWindowId';
+        window.location = url;
+    }
+}
+
+function eraseRequestCookie() {
+    var requestToken = getUrlParameter('dsRid'); // random request param
+    if (requestToken) {
+        var cookieName = 'dsiWindowId-' + requestToken;
+        var date = new Date();
+        date.setTime(date.getTime()-(10*24*60*60*1000)); // - 10 day
+        var expires = "; expires="+date.toGMTString();
+        document.cookie = cookieName+"="+expires+"; path=/";
+    }
+}
+
+var ajaxOnClick = function ajaxDecorateClick(event) {
+    if (event.status=="success") {
+        applyOnClick();
+    }
+}
+
+var oldWindowOnLoad = window.onload;
+
+window.onload = function(evt) {
+    try {
+        (oldWindowOnLoad)? oldWindowOnLoad(evt): null;
+    } finally {
+        eraseRequestCookie(); // manually erase the old dsRid cookie because Firefox doesn't do it properly
+        assertWindowId();
+        if (isHtml5()) {
+            applyOnClick();
+            jsf.ajax.addOnEvent(ajaxOnClick);
+        }
+    }
+}
+})();

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/45770596/deltaspike/modules/jsf/impl/src/main/resources/static/windowhandler.html
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/resources/static/windowhandler.html b/deltaspike/modules/jsf/impl/src/main/resources/static/windowhandler.html
new file mode 100644
index 0000000..c096722
--- /dev/null
+++ b/deltaspike/modules/jsf/impl/src/main/resources/static/windowhandler.html
@@ -0,0 +1,170 @@
+<!DOCTYPE html
+  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<html>
+
+<head><title>Loading...</title></head>
+<body $$bodyAttributes$$><div id="message" style="position:absolute;left:40%;top:40%">
+    Your browser does not support JavaScript.
+    Click <a href="$$noscriptUrl$$">here</a> to continue without JavaScript.
+</div></body>
+
+<script type="text/javascript" >
+function isHtml5() {
+    try { return !!localStorage.getItem;
+    } catch(e) { return false; }
+}
+function unstringify(serialized) {
+    if (JSON) { return JSON.parse(serialized); }
+    return serialized.split("|||");
+}
+function getOldBody() {
+    if (window.name.length != null) {
+        return localStorage.getItem(window.name + '_body');
+    }
+}
+function getOldBodyAttrs() {
+    if (window.name.length != null) {
+        return localStorage.getItem(window.name + '_bodyAttrs');
+    }
+}
+function getOldCss() {
+    if (window.name.length != null) {
+        return unstringify(localStorage.getItem(window.name + '_css'));
+    }
+}
+
+function addCss(url) {
+    var newSS = document.createElement("style");
+    newSS.setAttribute("rel", "stylesheet");
+    newSS.setAttribute("type", "text/css");
+    newSS.appendChild(document.createTextNode("@import url(" +url + ");"));
+    document.getElementsByTagName("head")[0].appendChild(newSS);
+}
+
+function loadCss(clean) {
+    if (!isHtml5()) { // only do this stuff on html browsers
+        return;
+    }
+    var oldCss  = getOldCss();
+    if (window.name && oldCss) {
+        for (i=0; oldCss && i< oldCss.length; i++) {
+            addCss(oldCss[i]);
+        }
+        if (clean) {
+            localStorage.removeItem(window.name + '_css');
+        }
+    }
+}
+
+function replaceContent() {
+    if (!isHtml5()) { // only do this stuff on html browsers
+        document.getElementById('message').textContent = "Loading...";
+        return;
+    }
+    loadCss(false);
+
+    var oldBody = getOldBody();
+
+    if (window.name && oldBody) {
+        document.body.innerHTML = oldBody;
+
+        //X TODO should restore all attribs of the body tag
+        document.body.setAttribute("class", getOldBodyAttrs());
+        document.body.setAttribute("style", " cursor: wait !important;");
+
+        localStorage.removeItem(window.name + '_body');
+        localStorage.removeItem(window.name + '_bodyAttrs');
+
+        // overlay the doc with an un-clickable full-size div
+        var newDiv = document.createElement("div");
+        newDiv.setAttribute("style", "position:absolute; z-index:1000; background-color:transparent; top:0; left:0; width:100%; height: 100%");
+        newDiv.setAttribute("class", "fulldiv");
+        document.body.appendChild(newDiv);
+    } else {
+        document.getElementById('message').textContent = "Loading...";
+    }
+}
+
+function setUrlParam(baseUrl, paramName, paramValue) {
+    var query = baseUrl;
+    var vars = query.split(/&|\?/g);
+    var newQuery = "";
+    var iParam = 0;
+    var paramFound = false;
+    for (var i=0; vars != null && i < vars.length; i++) {
+        var pair = vars[i].split("=");
+        if (pair.length == 1) {
+            newQuery = pair[0];
+        } else {
+            if (pair[0] != paramName) {
+                var amp = iParam++ > 0 ? "&" : "?";
+                newQuery =  newQuery + amp + pair[0] + "=" + pair[1];
+            } else {
+                paramFound = true;
+                var amp = iParam++ > 0 ? "&" : "?";
+                newQuery =  newQuery + amp + paramName + "=" + paramValue;
+            }
+        }
+    }
+    if (!paramFound) {
+        var amp = iParam++ > 0 ? "&" : "?";
+        newQuery =  newQuery + amp + paramName + "=" + paramValue;
+    }
+    return newQuery;
+}
+
+replaceContent();
+
+window.onload = function() {
+    loadCss(true);
+    // this will be replaced in the phase listener
+    var windowId = '$$windowIdValue$$';
+    if (windowId == 'uninitializedWindowId') {
+        windowId = window.name
+    }
+    if (!windowId || windowId.length < 1) {
+        // request a new windowId
+        windowId = 'automatedEntryPoint';
+    }
+
+    window.name = windowId;
+
+    // uncomment the following line to debug the intermediate page
+    // if (!confirm('reload?')) { return true; }
+
+    // 3 seconds expiry time
+    var expdt = new Date();
+    expdt.setTime(expdt.getTime()+(3*1000));
+    var expires = "; expires="+expdt.toGMTString();
+
+    var requestToken = Math.floor(Math.random()*1001);
+    var newUrl = setUrlParam(window.location.href, "dsRid", requestToken);
+    newUrl = setUrlParam(newUrl, "windowId", windowId);
+
+    document.cookie = 'dsWindowId-' + requestToken + '=' + windowId + expires+"; path=/";
+
+    window.location = newUrl;
+}
+</script>
+
+</html>
+