All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sibvisions.rad.ui.vaadin.impl.VaadinUI Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2012 SIB Visions GmbH
 * 
 * Licensed 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.
 *
 *
 * History
 *
 * 17.10.2012 - [CB] - creation
 * 28.03.2013 - [JR] - set language from request
 * 20.03.2013 - [JR] - isPortletMode and isServletMode implemented
 * 29.04.2013 - [JR] - notifyReload implemented
 * 23.07.2013 - [JR] - use request language only if no language was configured/set
 * 11.08.2013 - [JR] - made it easier to extend this class
 * 11.08.2013 - [JR] - set error handler
 * 12.08.2013 - [JR] - parseUrlParams: specific server base in servlet mode 
 * 27.11.2013 - [JR] - support manual push mode support for notifyWriteRespone
 * 04.12.2013 - [JR] - #888: use portlet context for accessing "global" properties
 * 14.12.2014 - [TK] - getFileHandle: close listener added to stop manual pooling
 * 18.03.2014 - [JR] - #977: check if launcher is factory is available (no factory -> no UI)
 * 12.04.2014 - [JR] - #1008: downloader extension for portlet mode
 * 25.04.2014 - [JR] - #1020: fixed temp file creation
 * 10.09.2014 - [JR] - detach overwritten because of destroying via heartbeat and "manually" close() calls
 * 31.12.2014 - [JR] - replaced mobile detection
 * 06.02.2015 - [JR] - phase controller integrated
 * 29.10.2015 - [JR] - performInvokeLater in case of upload without push
 * 21.12.2016 - [JR] - #1714 (JVx): debug log
 * 10.01.2017 - [JR] - #1738: en/disable cookie support 
 * 28.02.2018 - [JR] - #1835: configurable cookie max age and set default to 30 days
 * 15.05.2019 - [JR] - #2029: use Page location instead of request URL
 * 11.08.2019 - [JR] - init factory in reload, if not already initialized
 */
package com.sibvisions.rad.ui.vaadin.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.UUID;

import jvx.rad.application.IApplication;
import jvx.rad.application.IDataConnector;
import jvx.rad.application.IFileHandleReceiver;
import jvx.rad.application.ILauncher;
import jvx.rad.application.genui.UILauncher;
import jvx.rad.genui.UIFactoryManager;
import jvx.rad.io.FileHandle;
import jvx.rad.io.IFileHandle;
import jvx.rad.remote.IConnectionConstants;
import jvx.rad.ui.IComponent;
import jvx.rad.ui.IDimension;
import jvx.rad.ui.IFactory;
import jvx.rad.ui.ILayout;
import jvx.rad.ui.IRectangle;
import jvx.rad.ui.UIException;
import jvx.rad.ui.event.UIComponentEvent;
import jvx.rad.util.EventHandler;
import jvx.rad.util.ExceptionHandler;
import jvx.rad.util.SilentAbortException;
import javax.servlet.http.Cookie;

import org.vaadin.viritin.util.BrowserCookie;

import com.handinteractive.mobile.UAgentInfo;
import com.sibvisions.rad.server.IRequest;
import com.sibvisions.rad.ui.LauncherUtil;
import com.sibvisions.rad.ui.vaadin.api.IVaadinUIPhaseController;
import com.sibvisions.rad.ui.vaadin.api.event.ApplicationEvent;
import com.sibvisions.rad.ui.vaadin.api.event.LauncherEvent;
import com.sibvisions.rad.ui.vaadin.api.event.UIPhaseEvent;
import com.sibvisions.rad.ui.vaadin.ext.VaCachedResource;
import com.sibvisions.rad.ui.vaadin.ext.VaClassResource;
import com.sibvisions.rad.ui.vaadin.ext.ui.extension.DownloaderExtension;
import com.sibvisions.rad.ui.vaadin.ext.ui.extension.UIExtension;
import com.sibvisions.rad.ui.vaadin.impl.annotation.Configuration;
import com.sibvisions.rad.ui.vaadin.impl.annotation.Parameter;
import com.sibvisions.rad.ui.vaadin.impl.celleditor.ShortcutHandler;
import com.sibvisions.rad.ui.vaadin.impl.container.AbstractVaadinFrame;
import com.sibvisions.rad.ui.vaadin.impl.container.AbstractVaadinWindow;
import com.sibvisions.rad.ui.vaadin.impl.event.UIHandler;
import com.sibvisions.rad.ui.vaadin.impl.layout.VaadinClientBorderLayout;
import com.sibvisions.rad.ui.vaadin.server.VaadinErrorHandler;
import com.sibvisions.rad.ui.vaadin.server.VaadinServletService;
import com.sibvisions.rad.ui.vaadin.server.VaadinStreamResource;
import com.sibvisions.rad.ui.vaadin.server.communication.StaticDownloadHandler;
import com.sibvisions.util.ChangedHashtable;
import com.sibvisions.util.KeyValueList;
import com.sibvisions.util.Reflective;
import com.sibvisions.util.SecureHash;
import com.sibvisions.util.log.LoggerFactory;
import com.sibvisions.util.type.CodecUtil;
import com.sibvisions.util.type.CommonUtil;
import com.sibvisions.util.type.FileUtil;
import com.sibvisions.util.type.LocaleUtil;
import com.sibvisions.util.type.ResourceUtil;
import com.sibvisions.util.type.StringUtil;
import com.sibvisions.util.type.TimeZoneUtil;
import com.sibvisions.util.xml.XmlNode;
import com.sibvisions.util.xml.XmlWorker;
import com.vaadin.annotations.Theme;
import com.vaadin.server.BootstrapFragmentResponse;
import com.vaadin.server.BootstrapListener;
import com.vaadin.server.BootstrapPageResponse;
import com.vaadin.server.ClientConnector;
import com.vaadin.server.DownloadStream;
import com.vaadin.server.ExternalResource;
import com.vaadin.server.FileDownloader;
import com.vaadin.server.Page;
import com.vaadin.server.Page.BrowserWindowResizeEvent;
import com.vaadin.server.Page.BrowserWindowResizeListener;
import com.vaadin.server.RequestHandler;
import com.vaadin.server.VaadinPortlet;
import com.vaadin.server.VaadinPortletRequest;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinResponse;
import com.vaadin.server.VaadinService;
import com.vaadin.server.VaadinServlet;
import com.vaadin.server.VaadinServletRequest;
import com.vaadin.server.VaadinSession;
import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.BorderStyle;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Component;
import com.vaadin.ui.ConnectorTracker;
import com.vaadin.ui.JavaScript;
import com.vaadin.ui.ProgressBar;
import com.vaadin.ui.SingleComponentContainer;
import com.vaadin.ui.UI;
import com.vaadin.ui.Upload;
import com.vaadin.ui.Upload.FailedEvent;
import com.vaadin.ui.Upload.FinishedEvent;
import com.vaadin.ui.Upload.FinishedListener;
import com.vaadin.ui.Upload.ProgressListener;
import com.vaadin.ui.Upload.StartedEvent;
import com.vaadin.ui.Upload.StartedListener;
import com.vaadin.ui.Upload.SucceededEvent;
import com.vaadin.ui.Upload.SucceededListener;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import com.vaadin.ui.Window.CloseEvent;
import com.vaadin.ui.Window.CloseListener;

/**
 * The VaadinUI is the topmost component of any JVx vaadin Application. It provides access to the 
 * {@link UI} and adds the vaadin {@link ILauncher} implementation as {@link Component} to itself.
 * 
 * The UI uses jvx as theme name.
 * 
 * @author Benedikt Cermak
 * @see com.vaadin.ui.UI
 */
@Theme("jvx")
public class VaadinUI extends UI 
                      implements Serializable,
                                 BootstrapListener
{
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Class members
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    /** the property name for the main class. */
    protected static final String PARAM_MAIN = "main";
    /** the property name for the config. */
    protected static final String PARAM_CONFIG = "config";
    /** the property name for the cookies. */
    protected static final String PARAM_COOKIES = "cookies";
    /** the property name for the cookies max age. */
    protected static final String PARAM_COOKIES_MAXAGE = "cookies.maxAge";
    
    /** the property name for th unique identifier. */
    public static final String PARAM_UNIQUEIDENTIFIER = "Launcher.uniqueIdentifier";
    /** the property name for the portlet portal information. */
    public static final String PARAM_PORTLET = "portlet";
    /** the property name for the request URI. */
    public static final String PARAM_REQUESTURI = "Application.requestURI";
    /** the property name for the request URL. */
    public static final String PARAM_REQUESTURL = "Application.requestURL";
    /** the property name for the preserve on refresh option. */
    public static final String PARAM_PRESERVEONREFRESH = "preserveOnRefresh";
    /** the property name of an external CSS file. */
    public static final String PARAM_EXTERNALCSS = "externalCss";
    /** the property name for mobile view customization. */
    public static final String PARAM_MOBILEVIEW = "mobileView";
    /** the property name for mobile view scaling. */
    public static final String PARAM_MOBILEVIEW_SCALE = "mobileView.scale";
    /** the property name for phase controller. */
    public static final String PARAM_PHASE_CONTROLLER = "phaseController";
    /** the property name of table implementation. */
    public static final String PARAM_TABLEIMPL = "tableImpl";
    /** the property name of tree implementation. */
    public static final String PARAM_TREEIMPL = "treeImpl";
    /** the property name of tree implementation. */
    public static final String PARAM_CHARTIMPL = "chartImpl";
    /** the property name of layout implementation. */
    public static final String PARAM_LAYOUTIMPL = "layoutImpl";
    /** the property name of map implementation. */
    public static final String PARAM_MAPIMPL = "mapImpl";
    /** the property name for the polling interval in push mode (-1 to disable). */
    public static final String PARAM_POLLINGINTERVAL = "push.pollingInterval";
    /** the property name for the session timeout in seconds (-1 to disable). */
    public static final String PARAM_TIMEOUT = "sessionTimeout";

    /** the name of the mobile property. */
    public static final String PROP_MOBILE = "Web.mobile";
    /** the name of the mobile phone property. */
    public static final String PROP_PHONE = "Web.mobile.phone";
    /** the name of the tablet property. */
    public static final String PROP_TABLET = "Web.mobile.tablet";
    /** the name of the user-agent property. */
    public static final String PROP_USERAGENT = "Web.useragent";
    /** the name of the theme property. */
    public static final String PROP_THEME = "Web.theme";

    /** the name of the IOS property. */
    private static final String PROP_IOS = "Web.mobile.ios";
    /** the name of the Android property. */
    private static final String PROP_ANDROID = "Web.mobile.android";
    
    /** the root node identifier for application configuration xml files. */
    private static final String CONFIG_ROOT_NODE = "application";

    /** the ILauncher that represents this applet. */
    private transient VaadinUILauncher launcher;
    
    /** a Map with all windows. Every window is linked to the VaadinWindow. **/
    private transient HashMap hmpWindows = new HashMap();
    
    /** the object cache map. */
    private transient HashMap hmpObjects = new HashMap();

    /** a Map with all known cached resources. */
    private static transient HashMap hmpResourceCache = new HashMap();
    
    /** a Map with all cached resource names. */
    private static transient HashMap hmpResourceNames = new HashMap();
    
    /** a Map with all cached md5 resource names. */
    private static transient KeyValueList kvlResourceNameMd5 = new KeyValueList();
    
    /** the browser agent info. */
    private transient UAgentInfo agentInfo;
    
    /** the "reload" event. */
    private transient UIHandler eventReload;
    
    /** the ShortcutHandler for the ui. **/
    private ShortcutHandler shortcutHandler = new ShortcutHandler();

    /** the connector tracker. */
    private InternalConnectorTracker contrack;
    
    /** the destroy sync object. */
    private transient Object oSyncDestroy = new Object();

    /** the phase controller, if used. */
    private IVaadinUIPhaseController controller;
    
    /** the UI extension. */
    private UIExtension uiext;
    
    /** The {@link Registration} for the bootstrap listener. */
    private Registration bootstrapListenerRegistration = null;

    /** the unique UI identifier. */
    private String sIdentifier = UUID.randomUUID().toString();
    
    /** the identity object (JVM unique). */
    private static Object oIdentity = new Object();

    /** the cache for cached resource count. */
    private static int iCachedResourcesCount = 0;

    /** max age of a cookie in seconds (default: 30 days). */
    private int iCookieMaxAge = 2592000;

    /** application start time. */
    private long lStartTime;

    /** the last UI request time. */
    private long lLastRequest = -1; 
    
    /** Ignore performClosing. **/
    private boolean bIgnoreRemove = false;   
    
    /** whether {@link #doInit(VaadinRequest, int, String)} was finished. */
    private boolean bInitDone = false;
    
    /** whether to use cookies. */
    private boolean bUseCookies = true;
    
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Overwritten methods
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    /**
     * {@inheritDoc}
     */
    @Override
    public void doInit(VaadinRequest pRequest, int pUUId, String pEmbedId) 
    {
        bInitDone = false;

        try
        {
            super.doInit(pRequest, pUUId, pEmbedId);
        }
        finally
        {
            bInitDone = true;
        }
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public void doRefresh(VaadinRequest pRequest) 
    {
    	super.doRefresh(pRequest);
    	
    	VaadinService service = pRequest.getService();
    	
    	if (service instanceof VaadinServletService)
    	{
    		if (((VaadinServletService)service).isPreserveUIOnRefresh())
    		{
    			boolean bInit = UIFactoryManager.getFactory() == null;
    			
    			if (bInit)
    			{
    				notifyBeforeUI();
    			}
    			    			
    			Page page = getPage();
    			page.updateLocation(page.getLocation().toString(), false, true);
    			
    			if (bInit)
    			{
    				notifyAfterUI();
    			}
    		}
    	}
    }

    /**
     * Initializes this UI.
     * 
     * The parameter "main" should give the full qualified class name of
     * the application to run. The parameter "config" should give the full qualified
     * resource name of the application configuration xml file.
     * 
     * @param pRequest the {@link VaadinRequest}
     */
    @Override
    public void init(VaadinRequest pRequest)
    {
        setErrorHandler(new VaadinErrorHandler());

        controller = createPhaseController();
        
        //URL Parameter
        HashMap hmpParams = parseUrlParams(pRequest);
        
        //Parameter from annotation
        mergeParameter(hmpParams, this);
        
        agentInfo = checkBrowser(hmpParams);

        ApplicationConfig config = getApplicationConfig(hmpParams);
        
        String sApplicationClassName = config.getClassName();
        String sConfig = config.getConfigPath();
        
        String sCookies = null;
        String sCookieMaxAge = null;
        
        //Servlet, Portlet parameter
        if (VaadinServlet.getCurrent() != null)
        {
            VaadinServlet servlet = VaadinServlet.getCurrent();
            
            sCookies = servlet.getInitParameter(PARAM_COOKIES);
            sCookieMaxAge = servlet.getInitParameter(PARAM_COOKIES_MAXAGE);
            
            if (sApplicationClassName == null)
            {
                sApplicationClassName = servlet.getInitParameter(PARAM_MAIN);
            }
            
            if (sConfig == null)
            {
                sConfig = servlet.getInitParameter(PARAM_CONFIG);
            }

            mergeParameter(hmpParams, servlet);

            String sCss = hmpParams.get(PARAM_EXTERNALCSS);
            
            if (StringUtil.isEmpty(sCss))
            {
                sCss = ((VaadinServletService)VaadinService.getCurrent()).getHotDeploymentProperty(PARAM_EXTERNALCSS);
            }
            
            if (!StringUtil.isEmpty(sCss))
            {
                String sURI = hmpParams.get(PARAM_REQUESTURI);
                
                if (!sURI.endsWith("/"))
                {
                    //the URI should end with / (loading a stylesheet with ../ wouldn't work if not ending with /) 
                    if (sCss.startsWith("../"))
                    {
                        sCss = sCss.substring(3);
                    }
                }
                
                addCustomCss(sCss);
            }
        }
        else if (VaadinPortlet.getCurrent() != null)
        {
            //Use portlet context parameter as first choice (= global for all portlets)
            //Second choice are init parameter
            
            //"web.xml" context-param
            
            VaadinPortlet portlet = VaadinPortlet.getCurrent();

            javax.portlet.PortletContext ctxt = portlet.getPortletContext();

            sCookies = ctxt.getInitParameter("vaadinui." + PARAM_COOKIES);
            sCookieMaxAge = ctxt.getInitParameter("vaadinui." + PARAM_COOKIES_MAXAGE);
            
            //We use special prefix to avoid problems with other libraries!
            
            if (sApplicationClassName == null)
            {
                sApplicationClassName = (String)ctxt.getInitParameter("vaadinui." + PARAM_MAIN);
                sConfig = (String)ctxt.getInitParameter("vaadinui." + PARAM_CONFIG);
            }

            String sName;
            String sParamName;
            
            for (Enumeration en = ctxt.getInitParameterNames(); en.hasMoreElements();)
            {
                sName = (String)en.nextElement();
                
                if (sName.startsWith("vaadinui."))
                {
                    sParamName = sName.substring(9);
                    
                    if (!hmpParams.containsKey(sParamName))
                    {
                        hmpParams.put(sParamName, ctxt.getInitParameter(sName));
                    }
                }
            }
            
            //"portlet.xml" init-param

            if (StringUtil.isEmpty(sCookies))
            {
                sCookies = portlet.getInitParameter(PARAM_COOKIES);
            }
            
            if (!StringUtil.isEmpty(sCookieMaxAge))
            {
                try
                {
                    iCookieMaxAge = Integer.parseInt(sCookieMaxAge);
                }
                catch (Exception e)
                {
                    //ignore
                }
            }
            
            if (sApplicationClassName == null)
            {
                sApplicationClassName = portlet.getInitParameter(PARAM_MAIN);
                sConfig = portlet.getInitParameter(PARAM_CONFIG);
            }
            
            for (Enumeration en = portlet.getInitParameterNames(); en.hasMoreElements();)
            {
                sName = (String)en.nextElement();
                
                if (!hmpParams.containsKey(sName))
                {
                    hmpParams.put(sName, portlet.getInitParameter(sName));
                }
            }
            
            //Portlet
            hmpParams.put(PARAM_PORTLET, Boolean.TRUE.toString());
            
            //reload support
            bootstrapListenerRegistration = getSession().addBootstrapListener(this);
        }   
        
        if (!StringUtil.isEmpty(sCookies))
        {
            bUseCookies = Boolean.parseBoolean(sCookies);
        }
        
        //not available for the application
        hmpParams.remove(PARAM_MAIN);
        hmpParams.remove(PARAM_CONFIG);
        hmpParams.remove(PARAM_COOKIES);

        if (sApplicationClassName == null || sApplicationClassName.length() == 0)
        {
            throw new UIException("The '" + PARAM_MAIN + "' parameter was not found!");
        }
        
        Locale clientLocale = pRequest.getLocale();
        
        hmpParams.put(IConnectionConstants.CLIENT_LOCALE_LANGUAGE, clientLocale.getLanguage());
        hmpParams.put(IConnectionConstants.CLIENT_LOCALE_COUNTRY, clientLocale.getCountry());
        hmpParams.put(IConnectionConstants.CLIENT_LOCALE_VARIANT, clientLocale.getVariant());
        
        int offsetInMillis = getPage().getWebBrowser().getTimezoneOffset();
        int rawOffsetInMillis = getPage().getWebBrowser().getRawTimezoneOffset();

        hmpParams.put(IConnectionConstants.CLIENT_TIMEZONE_OFFSET, TimeZoneUtil.formatOffsetInMillis(offsetInMillis));
        hmpParams.put(IConnectionConstants.CLIENT_TIMEZONE_RAWOFFSET, TimeZoneUtil.formatOffsetInMillis(rawOffsetInMillis));
        hmpParams.put(IConnectionConstants.CLIENT_TIMEZONE, TimeZoneUtil.getBestMatchTimeZoneId(rawOffsetInMillis, clientLocale, offsetInMillis));
        
        if (agentInfo.detectWindows())
        {
            hmpParams.put(IConnectionConstants.CLIENT_FILE_ENCODING, "Cp1252");
        }
        else
        {
        	hmpParams.put(IConnectionConstants.CLIENT_FILE_ENCODING, System.getProperty("file.encoding"));
        }
        
        hmpParams.put(PARAM_UNIQUEIDENTIFIER, sIdentifier);
        
        if ((agentInfo.detectChrome() || agentInfo.detectFirefox()) && !Boolean.parseBoolean(hmpParams.get(PROP_MOBILE)))
        {
            //see https://github.com/vaadin/framework/issues/9846
            setMobileHtml5DndEnabled(true);
        }
        
        if (isServletMode())
        {
            setStyleName("jvxui");
        }
        else
        {
            setStyleName("jvxPortlet jvxui");
        }

        addRequestProperties(hmpParams, pRequest);
        
        String sPollingInterval = hmpParams.get(PARAM_POLLINGINTERVAL);
        
        if (!StringUtil.isEmpty(sPollingInterval))
        {
	        if (getPushConfiguration().getPushMode().isEnabled())
	        {
	        	try
	        	{
	        		setPollInterval(Integer.parseInt(sPollingInterval));
	        	}
	        	catch (Exception e)
	        	{
	        		//ignore
	        	}
	        }
        }
        
        String sTimeout = hmpParams.get(PARAM_TIMEOUT);
        
        if (!StringUtil.isEmpty(sTimeout))
        {
        	try
        	{
        		getSession().getSession().setMaxInactiveInterval(Integer.parseInt(sTimeout));
        	}
        	catch (Exception e)
        	{
                LoggerFactory.getInstance(VaadinUI.class).debug("Setting sessionTimeout in seconds failed! " + e.getMessage());
        	}
        }
        else
        {
            String sTimeoutInMinutes = hmpParams.get("session-timeout");
            
            if (sTimeoutInMinutes != null)
            {
                try
                {
                    int iTimeout = Integer.parseInt(sTimeoutInMinutes);
                    
                    if (iTimeout > 0)
                    {
                        iTimeout = iTimeout * 60;
                    }
                    
                    getSession().getSession().setMaxInactiveInterval(iTimeout);
                }
                catch (Exception e)
                {
                    LoggerFactory.getInstance(VaadinUI.class).debug("Setting session-timeout in minutes failed! " + e.getMessage());
                }
            }
        }
        
        setLauncher(createLauncher(sApplicationClassName, sConfig, hmpParams, readCookies(pRequest)));
        
        addActionHandler(shortcutHandler);
        
        lStartTime = System.currentTimeMillis();
    }

    /**
     * Refresh the appliacation if possible.
     * 
     * @param pRequest the refresh request
     */
    @Override
    public void refresh(VaadinRequest pRequest)
    {
    	if (launcher != null && launcher.application != null)
        {
    		IApplication app = launcher.application;
    		
    		if (app instanceof IDataConnector)
    		{
    			boolean bInit = UIFactoryManager.getFactory() == null;
    			
    			if (bInit)
    			{
    				notifyBeforeUI();
    			}
    			
    			try
    			{
	    			try
	    			{
	    				((IDataConnector)app).reload();
	    			}
	    			catch (Throwable th)
	    			{
	                    LoggerFactory.getInstance(VaadinUI.class).debug("Refresh UI failed!", th);
	    			}
    			}
    			finally
    			{
    				if (bInit)
    				{
    					notifyAfterUI();
    				}
    			}
    		}
        }
    	
    	super.refresh(pRequest);
    }
    
    /**
     * Removes the given window from the UI.
     * 
     * @param window the window.
     * @return true if the window is removed.
     */
    @Override
    public boolean removeWindow(Window window) 
    {
        //NO window closing event if "we" remove the window via our internal APIs,
        //but the event is important if Vaadin calls removeWindow!
        if (!bIgnoreRemove)
        {
            AbstractVaadinWindow win = hmpWindows.get(window);
            
            if (win != null)
            {
                if (!win.isDisposed())
                {
                    win.performWindowClosing();
                }
            }
        }

        return super.removeWindow(window);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public InternalConnectorTracker getConnectorTracker() 
    {
        if (contrack == null)
        {
            contrack = new InternalConnectorTracker(this);
        }
        
        return contrack;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void close()
    {
        super.close();
        
        destroy();
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public void detach()
    {
        try
        {
            super.detach();
        }
        finally
        {
            destroy();
        }
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public void setTheme(String pTheme)
    {
        super.setTheme(pTheme);
        
        if (launcher != null && launcher.application != null)
        {
            launcher.setParameter(PROP_THEME, pTheme);
        }
    }
    
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Interface implementation
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    /**
     * {@inheritDoc}
     */
    @Override
    public void modifyBootstrapPage(BootstrapPageResponse pResponse)
    {
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void modifyBootstrapFragment(BootstrapFragmentResponse pResponse)
    {
        notifyBeforeUI();
        
        try
        {
            notifyReload();
        }
        finally
        {
            notifyAfterUI();
        }
    }
    
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // User-defined methods
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  

    /**
     * Gets the unique UI identifier.
     * 
     * @return the identifier
     */
    public String getIdentifier()
    {
    	return sIdentifier;
    }
    
    /**
     * Triggers forceLayout with a delay of 300ms.
     */
    public static void forceLayout()
    {
    	JavaScript js = JavaScript.getCurrent();
    	
    	if (js != null)
    	{
	        //ensure layout is correct
	        js.execute("setTimeout(function(){vaadin.forceLayout();}, 300);");
    	}
    }
    
    /**
     * Creates the launcher.
     * 
     * @param pApplicationClassName the full qualified class name of the {@link IApplication} to run
     * @param pConfigName the config
     * @param pParams the parameters
     * @param pRegistry the Cookies
     * @return the launcher
     */
    protected VaadinUILauncher createLauncher(String pApplicationClassName, String pConfigName, HashMap pParams, Hashtable pRegistry)
    {
        return new VaadinUILauncher(this, pApplicationClassName, pConfigName, pParams, pRegistry);
    }
    
    /**
     * Sets the launcher.
     * 
     * @param pLauncher the launcher
     */
    protected void setLauncher(VaadinUILauncher pLauncher)
    {
        launcher = pLauncher;
    }
    
    /**
     * Gets the UI start time.
     * 
     * @return the time in millis
     */
    public long getStartTime()
    {
        return lStartTime;
    }
    
    /**
     * Gets the application configuration.
     * 
     * @param pURLParameter the parsed URL parameters
     * @return the application configuration
     */
    protected ApplicationConfig getApplicationConfig(HashMap pURLParameter)
    {
        return new ApplicationConfig(pURLParameter.get("main"), pURLParameter.get("config"));       
    }
    
    /**
     * Notifies the launcher that it is being reclaimed and that it should destroy any allocated resources.
     */
    public void destroy()
    {
        synchronized(oSyncDestroy)
        {
            if (launcher != null)
            {
                try
                {
                    notifyBeforeUI();
    
                    try
                    {
                        VaadinSession session = getSession();
                                
                        boolean bUnlock = false;
                        
                        if (session != null)
                        {
                        	if (bootstrapListenerRegistration != null)
                        	{
                        		bootstrapListenerRegistration.remove();
                        	}
                            
                            if (!session.hasLock())
                            {
                                bUnlock = true;
                                
                                //possible, if called via SessionListener
                                session.lock();
                            }
                        }
                        
                        try
                        {
                            if (uiext != null)
                            {
                                uiext.remove();
                            }
                        }
                        catch (Exception e)
                        {
                            LoggerFactory.getInstance(VaadinUI.class).debug("Removing UIExtension from target failed!", e);
                        }
                        
                        try
                        {
                            launcher.dispose();
                            launcher = null;
                        }
                        finally
                        {
                            if (bUnlock)
                            {
                                session.unlock();
                            }
                        }
                    }
                    finally
                    {
                        notifyAfterUI();
                    }
                }
                catch (Throwable t)
                {
                    LoggerFactory.getInstance(VaadinUI.class).error("Destroying application failed!", t);
                    
                    try
                    {
                        launcher.dispose();
                        launcher = null;
                    }
                    catch (Throwable th)
                    {
                        LoggerFactory.getInstance(VaadinUI.class).error("Destroying application (force) failed!", t);
                    }
                }
            }
            else
            {
                try
                {
                    if (uiext != null)
                    {
                        uiext.remove();
                    }
                }
                catch (Exception e)
                {
                    //ignore
                }
            }
        }
    }

    /**
     * Notification before an UI action is performed.
     */
    public void notifyBeforeUI()
    {
        IFactory factory = getFactory();
        
        //this is possible if session will be destroyed, because our application will be destroyed before super call 
        //see VaadinServletService#fireSessionDestroy.
        //
        //Because of PushHandler.disconnect it's possible that this method will be called, but the UI is already destroyed!
        if (factory != null)
        {
            UIFactoryManager.registerThreadFactoryInstance(factory);
            LocaleUtil.setThreadDefault(launcher.locale);
            TimeZoneUtil.setThreadDefault(launcher.timeZone);
        }
    }

    /**
     * Notification about a "standard" request start.
     */
    public void notifyRequestStart()
    {
        getConnectorTracker().setExecuted(false);
    }
    
    /**
     * Notification about a "standard" request end.
     */
    public void notifyRequestEnd()
    {
        getConnectorTracker().setExecuted(false);
    }
    
    /**
     * Notification after an UI action was performed.
     */
    public void notifyAfterUI()
    {
        LocaleUtil.setThreadDefault(null);
        TimeZoneUtil.setThreadDefault(null);
        UIFactoryManager.unregisterThreadFactoryInstance();
    }
    
    /**
     * Notifies all registered listeners that the UI should be reloaded.
     */
    public void notifyReload()
    {
        //reset "cached file", if not downloaded
        if (launcher != null)
        {
            launcher.resetInstances();
        }
        
        if (eventReload != null)
        {
            try
            {
                VaadinFactory factory = (VaadinFactory)getFactory(); 
                
                if (factory != null)
                {
                    factory.synchronizedDispatchEvent(eventReload, this);
                }
            }
            catch (Throwable th)
            {
                LoggerFactory.getInstance(VaadinUI.class).error("Reload UI failed!", th);
            }
        }
    }
    
    /**
     * Gets the UI factory.
     * 
     * @return the factory. This should be an instance of {@link VaadinFactory}.
     */
    public IFactory getFactory()
    {
        if (launcher != null)
        {
            return launcher.getFactory();
        }
        
        return null;
    }
    
    /**
     * Gets the current application instance.
     * 
     * @return the application instance
     */
    public IApplication getApplication()
    {
        if (launcher != null)
        {
            return launcher.application;
        }
        
        return null;
    }

    /**
     * Gets the agent info.
     * 
     * @return agent info
     */
    public UAgentInfo getAgentInfo()
    {
        return agentInfo;
    }
    
    /**
     * Adds the given window to the Hashmap windowMap and adds the window to the UI.
     * 
     * @param pWindow the vaadin window.
     * @param pVaadinWindow the AbstractVaadinWindow instance.
     */
    public void addWindow(Window pWindow, AbstractVaadinWindow pVaadinWindow)
    {
        hmpWindows.put(pWindow, pVaadinWindow);
        
        addWindow(pWindow);
    }

    /**
     * Removes the given window from the Hashmap windowMap.
     * 
     * @param pWindow the vaadin window.
     * @param pVaadinWindow the AbstractVaadinWindow instance.
     */
    public void removeWindow(Window pWindow, AbstractVaadinWindow pVaadinWindow)
    {
        bIgnoreRemove = true;
        
        try
        {
            removeWindow(pWindow);
        }
        finally
        {
            bIgnoreRemove = false;
        }
        
        hmpWindows.remove(pWindow);
    }    
    
    /**
     * Reads all cookies from the request.
     * 
     * @param pRequest the http request
     * @return all available cookies as key/value pair
     */
    private Hashtable readCookies(VaadinRequest pRequest)
    {
        if (bUseCookies)
        {
            Hashtable htCookies = new Hashtable();
            
            Cookie[] cookie = pRequest.getCookies();
    
            if (cookie != null)
            {
                for (int i = 0, anz = cookie.length; i < anz; i++)
                {
                    if (cookie[i].getName().startsWith("0x"))
                    {
                        String sValue;
                        
                        try
                        {
                            if (cookie[i].getValue().startsWith("0x"))
                            {
                                sValue = CodecUtil.decodeHex(cookie[i].getValue().substring(2));
                            }
                            else
                            {
                                sValue = cookie[i].getValue();
                            }
    
                            if (sValue != null && sValue.length() > 0)
                            {
                                htCookies.put(CodecUtil.decodeHex(cookie[i].getName().substring(2)), sValue);
                            }
                        }
                        catch (Exception ex)
                        {
                            htCookies.put(cookie[i].getName(), cookie[i].getValue());
                        }
                    }
                    else
                    {
                        htCookies.put(cookie[i].getName(), cookie[i].getValue());
                    }
                }
            }
            
            return htCookies;
        }
        else
        {
            return null;
        }
    }
    
    /**
     * Writes all available cookies.
     */
    private void writeCookies()
    {
        if (launcher != null)
        {
            writeCookies(VaadinService.getCurrentResponse(), launcher.getRegistryChanges());
        }
    }
    
    /**
     * Sets key/value pairs as response cookies.
     * 
     * @param pResponse the http response
     * @param pChanges the key/value pairs
     */
    private void writeCookies(VaadinResponse pResponse, List> pChanges)
    {
        if (bUseCookies && pChanges != null)
        {
        	//this is possible if another Thread uses a cached UI instance in a separate Thread to push to the client
        	//e.g. service calls
        	if (UI.getCurrent() != null)
        	{
	            for (Entry entry : pChanges)
	            {
	                try
	                {
	                    Cookie cookie;
	                    
	                    if (entry.getValue() == null)
	                    {
	                        //remove
	                        
	                        cookie = new Cookie("0x" + CodecUtil.encodeHex(entry.getKey()), "");
	                        cookie.setMaxAge(0);
	                    }
	                    else
	                    {
	                        //set/change
	
	                        cookie = new Cookie("0x" + CodecUtil.encodeHex(entry.getKey()), "0x" + CodecUtil.encodeHex(entry.getValue()));
	                        cookie.setMaxAge(iCookieMaxAge);
	                    }                    
	
	                    configureCookie(cookie);
	
	                    if (pResponse != null)
	                    {
	                        pResponse.addCookie(cookie);
	                    }
	                    else
	                    {
	                        BrowserCookie.setCookie(cookie);
	                    }
	                }
	                catch (UnsupportedEncodingException use)
	                {
	                    //nothing to be done
	                }
	            }
        	}
        }
    }   
    
    /**
     * Configures the given cookie.
     * 
     * @param pCookie the cookie
     */
    protected void configureCookie(Cookie pCookie)
    {
    	pCookie.setPath(VaadinService.getCurrentRequest().getContextPath());    	
    }
    
    /**
     * Parses the parameters from the current request. The parameters are available
     * through the {@link ILauncher} implementation.
     * 
     * @param pRequest the request to use or null to use the current request
     * @return HashMap with the parameters
     * @see ILauncher#getParameter(String)
     */
    public static HashMap parseUrlParams(VaadinRequest pRequest)
    {
        HashMap hmpParams = new HashMap();
        
        try 
        {
            VaadinRequest request = pRequest;
            
            if (request == null)
            {
            	request = VaadinService.getCurrentRequest();
            }
            
            String sUrl = null;
            
            if (request instanceof VaadinServletRequest)
            {
                VaadinServletRequest servletRequest = (VaadinServletRequest)VaadinService.getCurrentRequest();

                if (servletRequest != null)
                {
	                String sURI = servletRequest.getRequestURI();
	                String sURL = servletRequest.getRequestURL().toString();
	                
	                
	                hmpParams.put(PARAM_REQUESTURI, sURI);
	                hmpParams.put(PARAM_REQUESTURL, sURL);
	                
	                String sServletPath = servletRequest.getServletPath();
	                
	                //#2029
	                //the Page Location is better than the request URL because it'll work if we are behind a proxy like mod_proxy
	                Page page = Page.getCurrent();
	                
	                if (page != null)
	                {
		                URI url = page.getLocation();
		                
		                if (url != null)
		                {
		                	sURL = url.toString();
		                }
	                }
	
	                int iPathPos = sURL.indexOf(sServletPath);
	                
	                if (iPathPos >= 0)
	                {
	                    //http://server:port/context/uipath/ui
	                    //possible: http://server:port/name/name/ui
	                    //It's possible that the context and uipath are equal
	                    int iNextPathPos = sURL.indexOf(servletRequest.getServletPath(), iPathPos + sServletPath.length());
	                    
	                    if (iNextPathPos >= 0)
	                    {
	                        iPathPos = iNextPathPos;
	                    }
	                    
	                    hmpParams.put(ILauncher.PARAM_SERVERBASE, sURL.substring(0, iPathPos));
	                }
	                else
	                {
	                    hmpParams.put(ILauncher.PARAM_SERVERBASE, sURL);
	                }
	                
	                sUrl = servletRequest.getQueryString();
                }
            }
            else
            {
                URI uriDocBase = Page.getCurrent().getLocation();

                if (uriDocBase != null)
                {
	                String sServer = uriDocBase.getScheme() + "://" + uriDocBase.getAuthority();
	                
	                String sPath = uriDocBase.getPath();
	                
	                if (sPath != null)
	                {
	                    int iPos = sPath.lastIndexOf('/');
	                    
	                    if (iPos >= 0)
	                    {
	                    	sServer += sPath.substring(0, iPos);
	                    }
	                }
	            
	                hmpParams.put(PARAM_REQUESTURI, sServer);
	                hmpParams.put(ILauncher.PARAM_SERVERBASE, sServer);
	                
	                sUrl = uriDocBase.getQuery();
                }
            }
    
            if (sUrl != null && sUrl.trim().length() > 0)
            {
                StringTokenizer tok = new StringTokenizer(sUrl, "&");
                
                String sParam;
                
                int iPos;
                
                
                while (tok.hasMoreTokens())
                {
                    sParam = tok.nextToken();
                    
                    iPos = sParam.indexOf('=');
                    
                    if (iPos > 0)
                    {
                        hmpParams.put(sParam.substring(0, iPos), CodecUtil.decodeURLParameter(sParam.substring(iPos + 1)));
                    }
                }
            }
            
            if (request != null)
            {
				String sUser = request.getRemoteUser();
				
				if (sUser != null)
				{
					hmpParams.put(IRequest.PROP_REMOTE_USER, sUser);
				}
				
				hmpParams.put(IRequest.PROP_REMOTE_ADDRESS, request.getRemoteAddr());
				hmpParams.put(IRequest.PROP_REMOTE_HOST, request.getRemoteHost());
            }
        }
        catch (Exception e)
        {
            LoggerFactory.getInstance(VaadinUI.class).error("Parameter load error!", e);
        }
        
        return hmpParams;
    }

    /**
     * Checks mobile browser support.
     * 
     * @param pParams the application parameter
     * @return the parsed agent info
     */
    public static UAgentInfo checkBrowser(HashMap pParams)
    {
        VaadinRequest request = VaadinService.getCurrentRequest();

        String sAgent = request.getHeader("User-Agent");
        
        pParams.put(PROP_USERAGENT, sAgent);
        
        //http://blog.mobileesp.com/
        //http://www.hand-interactive.com/m/resources/detect-mobile-java.htm
        UAgentInfo ua = new UAgentInfo(sAgent, request.getHeader("Accept"));
        
        if (ua.isTierTablet || ua.isMobilePhone)
        {
            pParams.put(PROP_MOBILE, "true");
        }
        
        if (ua.isMobilePhone)
        {
            pParams.put(PROP_PHONE, "true");
        }

        if (ua.isTierTablet)
        {
            pParams.put(PROP_TABLET, "true");
        }

        if (ua.detectAndroid())
        {
            pParams.put(PROP_ANDROID, "true");
        }
        
        if (ua.detectIos())
        {
            pParams.put(PROP_IOS, "true");
        }
        
        return ua;
    }
    
    /**
     * Adds request parameter to the given parameters.
     * 
     * @param pParams the parameters
     * @param pRequest the initial request
     */
    protected void addRequestProperties(HashMap pParams, VaadinRequest pRequest)
    {
        String sProp = pRequest.getAuthType();
        
        if (sProp != null)
        {
            pParams.put(IRequest.PROP_AUTHENTICATION_TYPE, sProp);
        }
        
        sProp = pRequest.getRemoteUser();
        
        if (sProp != null)
        {
            pParams.put(IRequest.PROP_REMOTE_USER, sProp);
        }
        
        pParams.put(IRequest.PROP_REMOTE_ADDRESS, pRequest.getRemoteAddr());
        pParams.put(IRequest.PROP_REMOTE_HOST, pRequest.getRemoteHost());

        if (pRequest instanceof VaadinServletRequest)
        {
            VaadinServletRequest servletRequest = (VaadinServletRequest)VaadinService.getCurrentRequest();
        
            pParams.put(IRequest.PROP_URI, servletRequest.getRequestURI());
        }
    }
    
    /**
     * Merges the given parameter with servlet init parameter.
     * 
     * @param pParameter current parameter
     * @param pServlet the servlet to use
     */
    public static void mergeParameter(HashMap pParameter, VaadinServlet pServlet)
    {
        String sName;
        
        for (Enumeration en = pServlet.getInitParameterNames(); en.hasMoreElements();)
        {
            sName = (String)en.nextElement();
            
            if (!pParameter.containsKey(sName))
            {
                pParameter.put(sName, pServlet.getInitParameter(sName));
            }
        }
    }
    
    /**
     * Reads all configuration annotations from the given UI and merges the fond key/value pairs with
     * already available parameters. Only new parameters will be added.
     * 
     * @param pParameter the already available parameters
     * @param pUI the annotated UI
     */
    private void mergeParameter(HashMap pParameter, UI pUI)
    {
        Configuration cfg = pUI.getClass().getAnnotation(Configuration.class);
        
        if (cfg != null)
        {
            Parameter[] param = cfg.value();
            
            if (param != null)
            {
                String sName;

                for (Parameter par : param)
                {
                    sName = par.name();
                    
                    if (!pParameter.containsKey(sName))
                    {
                        pParameter.put(sName, par.value());
                    }
                }
            }
        }
    }   
    
    /**
     * Gets the launcher.
     * 
     * @return the launcher.
     */
    public VaadinUILauncher getLauncher()
    {
        return launcher;
    }
    
    /**
     * Gets whether we are in portlet mode. Don't use this method with standard application servers (without portlet API)
     * otherwise a {@link ClassNotFoundException} will occur.
     * 
     * @return true if the last request was a portlet request, false otherwise
     */
    public static boolean isPortletMode()
    {
        VaadinRequest request = VaadinService.getCurrentRequest();
        
        return request != null && request instanceof VaadinPortletRequest;
    }
    
    /**
     * Gets whether we are in servlet mode.
     * 
     * @return true if the last request was a servlet request, false otherwise
     */
    public static boolean isServletMode()
    {
        VaadinRequest request = VaadinService.getCurrentRequest();

        return request == null || request instanceof VaadinServletRequest;
    }
    
    /**
     * Gets whether {@link #doInit(VaadinRequest, int, String)} was finished.
     * 
     * @return true if init was finished, false otherwise (e.g. an Exceptin occured during init)
     */
    public boolean isInitDone()
    {
        return bInitDone;
    }
    
    /**
     * Creates a new instance of {@link IVaadinUIPhaseController} with application class loader.
     * 
     * @return the phase controller or null if no controller class was configured or
     *         initialization failed
     */
    protected IVaadinUIPhaseController createPhaseController()
    {
        String sPhaseControllerClass;
        
        if (VaadinServlet.getCurrent() != null)
        {
            VaadinServlet servlet = VaadinServlet.getCurrent();
            
            sPhaseControllerClass = servlet.getInitParameter(PARAM_PHASE_CONTROLLER);
            
            if (StringUtil.isEmpty(sPhaseControllerClass))
            {
                VaadinService service = VaadinService.getCurrent();
                
                sPhaseControllerClass = ((VaadinServletService)service).getHotDeploymentProperty(PARAM_PHASE_CONTROLLER);
            }
        }
        else if (VaadinPortlet.getCurrent() != null)
        {
            //Use portlet context parameter as first choice (= global for all portlets)
            //Second choice are init parameter
            
            //"web.xml" context-param
            
            VaadinPortlet portlet = VaadinPortlet.getCurrent();

            javax.portlet.PortletContext ctxt = portlet.getPortletContext();

            //We use special prefix to avoid problems with other libraries!
            sPhaseControllerClass = (String)ctxt.getInitParameter("vaadinui." + PARAM_PHASE_CONTROLLER);
        }
        else
        {
            sPhaseControllerClass = null;
        }
        
        if (!StringUtil.isEmpty(sPhaseControllerClass))
        {
            try
            {
                Class clazz = Class.forName(sPhaseControllerClass, true, getApplicationClassLoader());
                
                return (IVaadinUIPhaseController)clazz.newInstance();
            }
            catch (Exception e)
            {
                LoggerFactory.getInstance(VaadinUI.class).error("Initialization of phase controller '", sPhaseControllerClass, "' failed!", e);
            }
        }
        
        return null;
    }
    
    /**
     * Creates the application instance.
     * 
     * @param pLauncher the launcher
     * @param pApplicationClassName the application class name
     * @return the application instance
     * @throws Throwable if application creation fails
     */
    protected IApplication createApplication(UILauncher pLauncher, String pApplicationClassName) throws Throwable
    {
        return LauncherUtil.createApplication(pLauncher, getApplicationClassLoader(), pApplicationClassName);
    }
    
    /**
     * Gets the application class loader. This is usually the current context class loader.
     * 
     * @return the class loader
     */
    protected ClassLoader getApplicationClassLoader()
    {
        return Thread.currentThread().getContextClassLoader();
    }
    
    /**
     * Creates a new instance of {@link VaClassResource} for the given resource. The resource will be loaded
     * with the application class loader.
     * 
     * @param pResourceName the resource name/path
     * @return the class resource
     */
    public VaClassResource createClassResource(String pResourceName)
    {
        return new VaClassResource(getApplicationClassLoader(), pResourceName);     
    }
    
    /**
     * Creates a new instance of {@link VaCachedResource} for the given resource or gets an already 
     * created instance. The resource will be loaded with the application class loader.
     * 
     * @param pResourceName the resource name/path
     * @return the cached or a new instance
     */
    public VaCachedResource createCachedResource(String pResourceName)
    {
        return createCachedResource(pResourceName, null);
    }
    
    /**
     * Creates a new instance of {@link VaCachedResource} for the given content or gets an already
     * created instance.
     * 
     * @param pResourceName the resource name
     * @param pContent the content
     * @return the cached or a new instance
     */
    public VaCachedResource createCachedResource(String pResourceName, byte[] pContent)
    {
        if (pResourceName == null)
        {
            return null;
        }
        
        synchronized (hmpResourceNames)
        {
            String sResourceName = getIdentityCode() + "_" + pResourceName;
            
            if (pContent != null)
            {
                String sNewResourceName = sResourceName;
                
                try
                {
                    //cached by checksum
                    sNewResourceName += "_" + SecureHash.getHash("MD5", pContent);
                }
                catch (Exception e)
                {
                    //always new
                    sNewResourceName += "_" + System.currentTimeMillis();
                }
                
                kvlResourceNameMd5.put(sResourceName, sNewResourceName);
                
                sResourceName = sNewResourceName;
            }

            String sKey = hmpResourceNames.get(sResourceName);
            
            if (sKey != null)
            {
                return hmpResourceCache.get(sKey);
            }
            else
            {
                sKey = "" + iCachedResourcesCount;
                iCachedResourcesCount++;
        
                VaCachedResource cres;
                
                if (pContent == null)
                {
                    cres = new VaCachedResource(sKey, getApplicationClassLoader(), pResourceName);
                }
                else
                {
                    cres = new VaCachedResource(sKey, pResourceName, pContent);                
                }
    
                hmpResourceNames.put(sResourceName, sKey);
                hmpResourceCache.put(sKey, cres);
                
                return cres;
            }
        }
    }
    
    /**
     * Gets a cached resource from the cache.
     * 
     * @param pCacheKey the cache key
     * @return the resource or null if no resource was found
     */
    public static VaCachedResource getCachedResource(String pCacheKey)
    {
        return hmpResourceCache.get(pCacheKey);
    }
    
    /**
     * Removes a resource from the cache, if available.
     * 
     * @param pResourceName the resource name
     */
    public static void removeCachedResource(String pResourceName)
    {
        //don't remove resource from cache because client's could request the "old" resource
        synchronized (hmpResourceNames)
        {
            int iCode = getIdentityCode();

            String sResourceName = iCode + "_" + pResourceName;
            
            List liNames = kvlResourceNameMd5.remove(sResourceName);
            
            if (liNames != null)
            {
                for (String name : liNames)
                {
                    hmpResourceNames.remove(name);
                }
            }
            
            hmpResourceNames.remove(sResourceName);
        }
    }

    /**
     * Cleans the resource cache. Only resources with static (byte[]) will be removed.
     */
    public static void cleanupResourceCache()
    {
        synchronized (hmpResourceNames)
        {
            for (String key : kvlResourceNameMd5.keySet())
            {
                cleanupResourceCache(key);
            }
            
            kvlResourceNameMd5.clear();
        }
    }
    
    /**
     * Cleans the resource cache. Only the given resource will be removed, if it contains
     * static (byte[]) content.
     * 
     * @param pResourceName the resource name
     */
    public static void cleanupResourceCache(String pResourceName)
    {
        synchronized (hmpResourceNames)
        {
            List liNames = kvlResourceNameMd5.remove(pResourceName);
            
            if (liNames != null)
            {
                for (String name : liNames)
                {
                    hmpResourceCache.remove(hmpResourceNames.remove(name));
                }
            }
        }
    }
    
    /**
     * Returns the ShortcutHandler.
     * 
     * @return the ShortcutHandler.
     */
    public ShortcutHandler getShortcutHandler()
    {
        return shortcutHandler;
    }
    
    /**
     * Gets the identity hash code of VaadinUI. The code is the JVM identity hash code of
     * a static object.
     * 
     * @return the identity code
     */
    public static int getIdentityCode()
    {
        return System.identityHashCode(oIdentity);
    }
    
    /**
     * Adds a custom CSS file to the page.
     * 
     * @param pURL the CSS URL
     */
    protected void addCustomCss(String pURL)
    {
        if (pURL.startsWith("jar!"))
        {
            String sCssName = pURL.substring(4);

            VaClassResource resource = new VaClassResource(sCssName);
            resource.setFilename(sCssName.substring(0, sCssName.length() - 4) + "_" + createCssIdentifier(pURL) + ".css");
            
            //use an internal resource
            Page.getCurrent().getStyles().add(resource);
        }
        else
        {
            //add an id to force reloading after every server restart
            Page.getCurrent().getStyles().add(new ExternalResource(pURL + "?id=" + createCssIdentifier(pURL)));
        }
    }

    /**
     * Creates a unique css identifier.
     * 
     * @param pURL the configured CSS URL
     * @return the css identifier
     */
    protected String createCssIdentifier(String pURL)
    {
        return Integer.toString(System.identityHashCode(VaadinService.getCurrent()));
    }
    
    /**
     * Executes tasks which should be executed after all dirty connectors were detected and before
     * invokeLater will be called.
     */
    protected void executePostConnectorTasks()
    {
        //for sub classes
    }
    
    /**
     * Sets the last request time.
     * 
     * @param pTimestamp the timestamp in millis
     */
    public void setLastRequestTimestamp(long pTimestamp)
    {
        lLastRequest = pTimestamp;
    }
    
    /**
     * Gets the last request time.
     * 
     * @return the timestamp in millis
     */
    public long getLastRequestTimestamp()
    {
        if (lLastRequest == -1)
        {
            lLastRequest = getSession().getLastRequestTimestamp();
        }
        
        return lLastRequest;
    }
    
    /**
     * Puts an object to the cache.
     * 
     * @param pName the name of the object
     * @param pValue the value
     */
    public void putObject(String pName, Object pValue)
    {
        if (pValue == null)
        {
            hmpObjects.remove(pName);
        }
        else
        {
            hmpObjects.put(pName, pValue);
        }
    }
    
    /**
     * Gets an object from the cache.
     * 
     * @param pName the name of the object
     * @return the cached value or null if no object was found with given name
     */
    public Object getObject(String pName)
    {
        return hmpObjects.get(pName);
    }

    /**
     * Gets the UI extension.
     * 
     * @return the {@link UIExtension}
     */
    public UIExtension getExtension()
    {
        if (uiext == null)
        {
            uiext = new UIExtension();
            uiext.extend(this);
        }
        
        return uiext;
    }    
    
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Events
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /**
     * Gets the event handler for the reload event.
     * 
     * @return the event handler
     */
    public UIHandler eventReload()
    {
        if (eventReload == null)
        {
            eventReload = new UIHandler("reload");
        }
        
        return eventReload;
    }
    
    //****************************************************************
    // Subclass definition
    //****************************************************************


    /**
     * The VaadinUILauncher class is the vaadin implementation of {@link ILauncher}.
     * It has full access to the {@link UI}.
     * 
     * @author Benedikt Cermak
     */
    public static class VaadinUILauncher extends AbstractVaadinFrame 
                                         implements ILauncher, 
                                                    Serializable
    {
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Class members
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        
        /** the {@link UILauncher} instance. */
        private UILauncher uilauncher;

        /** the UI. */
        private VaadinUI ui;

        /** the application implementation base. */
        private IApplication application = null;
        
        /** the locale. */
        private Locale locale = null;
        
        /** the time zone. */
        private TimeZone timeZone = null;
        
        /** the parameters of the ui. */
        private HashMap hmpParams = null;
        
        /** the changed hashtable for registry values. */
        private ChangedHashtable chtRegistry = null;
        
        /** Handels the Download. **/
        private VaadinRequestHandler requestHandler = new VaadinRequestHandler();
        
        /** the download extension (for portlets). */
        private DownloaderExtension downloader;

        /** the resize listener. */
        private BrowserWindowResizeListener bwinResizeListener;
        
        /** The {@link Registration} for the browser window resize listener. */
        private Registration windowResizeListenerRegistration = null;
        
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Initialization
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        /**
         * Creates a new instance of VaadinUILauncher.
         * 
         * @param pUI the VaadinUI.
         * @param pApplicationClassName the full qualified class name of 
         *        the {@link IApplication} to run.
         * @param pConfigName the config
         * @param pParams the parameters
         * @param pRegistry the Cookies
         */
        public VaadinUILauncher(VaadinUI pUI, String pApplicationClassName, String pConfigName, HashMap pParams, Hashtable pRegistry)
        {				
            super(pUI);
            
            //needed for push during constructor, otherwise we don't have a launcher and can't set the factory
            pUI.launcher = this;
            
            ui = pUI;
            
            hmpParams = pParams;
                        
            mergeConfiguration(pConfigName);
            
            //if no custom language was configured -> use the request language
            if (StringUtil.isEmpty(hmpParams.get(ILauncher.PARAM_APPLICATIONLANGUAGE)))
            {
                hmpParams.put(ILauncher.PARAM_APPLICATIONLANGUAGE, hmpParams.get(IConnectionConstants.CLIENT_LOCALE_LANGUAGE));
            }
            
            //if no custom language was configured -> use the request language
            if (StringUtil.isEmpty(hmpParams.get(ILauncher.PARAM_APPLICATIONTIMEZONE)))
            {
                hmpParams.put(ILauncher.PARAM_APPLICATIONTIMEZONE, hmpParams.get(IConnectionConstants.CLIENT_TIMEZONE));
            }
            
            hmpParams.put(PROP_THEME, ui.getTheme());
            
            //use initial registry parameters
            if (pRegistry != null)
            {
                chtRegistry = new ChangedHashtable();
                
                for (Map.Entry entry : pRegistry.entrySet())
                {
                    chtRegistry.put(entry.getKey(), entry.getValue(), false);
                }
            }           
    
            VaadinFactory factory;
                
            try
            {
                factory = (VaadinFactory)Reflective.construct(ui.getApplicationClassLoader(), getParameter(ILauncher.PARAM_UIFACTORY));
            }
            catch (Throwable th)
            {
                factory = new VaadinFactory();
                
                LoggerFactory.getInstance(VaadinUI.class).debug("Fallback to VaadinFactory", th);
            }
            
            //configure factory
            
            String sTableImpl = hmpParams.get(PARAM_TABLEIMPL);

            if (sTableImpl != null)
            {
                factory.setProperty(VaadinFactory.PROPERTY_COMPONENT_LEGACY_TABLE, "grid".equals(sTableImpl) ? Boolean.FALSE : Boolean.TRUE);
            }
            
            String sTreeImpl = hmpParams.get(PARAM_TREEIMPL);

            if (sTreeImpl != null)
            {
                factory.setProperty(VaadinFactory.PROPERTY_COMPONENT_LEGACY_TREE, "treegrid".equals(sTreeImpl) ? Boolean.FALSE : Boolean.TRUE);
            }
            
            String sChartImpl = hmpParams.get(PARAM_CHARTIMPL);
            
            if (sChartImpl != null)
            {
                factory.setProperty(VaadinFactory.PROPERTY_COMPONENT_CHARTJS, "chartjs".equals(sChartImpl) ? Boolean.TRUE : Boolean.FALSE);
            }
            
            String sLayoutImpl = hmpParams.get(PARAM_LAYOUTIMPL);
            
            if (sLayoutImpl != null)
            {
                factory.setProperty(VaadinFactory.PROPERTY_COMPONENT_CLIENT_LAYOUTS, "client".equals(sLayoutImpl) ? Boolean.TRUE : Boolean.FALSE);
            }
            
            String sMapImpl = hmpParams.get(PARAM_MAPIMPL);
            
            if (sMapImpl != null)
            {
                factory.setProperty(VaadinFactory.PROPERTY_COMPONENT_MAP_GOOGLE, "google".equals(sMapImpl) ? Boolean.TRUE : Boolean.FALSE);
            }            
            
            try
            {
            	factory.setUI(ui);
            }
            catch (Throwable th)
            {
            	handleException(th);
            	
            	return;
            }
            
            UIFactoryManager.registerThreadFactoryInstance(factory);
            
            pUI.getSession().addRequestHandler(requestHandler);
            
            setFactory(factory);
            
            uilauncher = new UILauncher(this);

            if (pUI.controller != null)
            {
                pUI.controller.phaseChanged(new LauncherEvent(UIPhaseEvent.PHASE_CONFIGURE_LAUNCHER, pUI, uilauncher));
            }
            
            try
            {
                application = ui.createApplication(uilauncher, pApplicationClassName);

                if (pUI.controller != null)
                {
                    pUI.controller.phaseChanged(new ApplicationEvent(UIPhaseEvent.PHASE_CONFIGURE_APPLICATION, pUI, application));
                }
                
                uilauncher.setTitle(application.getName());
                
                //add the application
                uilauncher.setLayout(new VaadinClientBorderLayout());
                uilauncher.add(application, VaadinClientBorderLayout.CENTER); 

                Component panRoot = getRootPane().getResource();
                
                panRoot.setStyleName("jvxapp");

                if (isServletMode())
                {
                    //Portlet defines the size. Don't set it here!
                    pUI.setSizeFull();
                }
                
                pUI.setContent(panRoot);

                getRootPane().setSizeFull();

                bwinResizeListener = new BrowserWindowResizeListener() 
                {
                    @Override
                    public void browserWindowResized(BrowserWindowResizeEvent event)
                    {
                        getRootPane().performLayout();
                        
                        if (eventComponentResized != null)
                        {
                        	VaadinFactory fact = getFactory();
                        	
                        	if (fact != null)
                        	{
                        		fact.synchronizedDispatchEvent(eventComponentResized, 
                        				                       new UIComponentEvent(eventSource, 
										                                            UIComponentEvent.COMPONENT_RESIZED, 
										                                            System.currentTimeMillis(),
										                                            0));
                        	}
                        }
                    }
                };
                
                windowResizeListenerRegistration = ui.getPage().addBrowserWindowResizeListener(bwinResizeListener);
        
                uilauncher.setVisible(true);

                if (pUI.controller != null)
                {
                    pUI.controller.phaseChanged(new ApplicationEvent(UIPhaseEvent.PHASE_BEFORE_NOTIFYVISIBLE, pUI, application));
                }
                
                application.notifyVisible();
            }
            catch (Throwable th)
            {
                handleException(th);
            }
            
            if (!isServletMode() || isAndroidDevice())
            {
                downloader = new DownloaderExtension();
                downloader.extend(ui);
            }

//            forceLayout();
        }

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Interface implementation
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        // IFRAME
        
        /**
         * {@inheritDoc}
         */
        public void toFront()
        {
        }   
        
        /**
         * {@inheritDoc}
         */
        public void centerRelativeTo(IComponent pComponent)
        {
        }
        
        //ILAUNCHER
        
        /**
         * {@inheritDoc}
         */
        public String getParameter(String pName) 
        {
            String sValue = null;
            
            //Use userdefined parameters before using the applet parameters
            if (hmpParams.containsKey(pName))
            {
                sValue = hmpParams.get(pName);
            }
            
            if (sValue != null)
            {
                sValue = sValue.replace("\\n", "\n");
                sValue = sValue.replace("
", "\n"); } return LauncherUtil.replaceParameter(sValue, this); } /** * {@inheritDoc} */ public void setParameter(String pName, String pValue) { hmpParams.put(pName, pValue); } /** * {@inheritDoc} */ public void showDocument(String pDocumentname, IRectangle pBounds, String pTarget) throws Exception { if (pBounds != null) { ui.getPage().open(pDocumentname, pTarget, pBounds.getWidth(), pBounds.getHeight(), BorderStyle.DEFAULT); } else { ui.getPage().open(pDocumentname, pTarget, true); } } /** * {@inheritDoc} */ @SuppressWarnings("deprecation") public void showFileHandle(final IFileHandle pFileHandle, IRectangle pBounds, String pTarget) throws Throwable { if (isAndroidDevice() && downloader != null) { downloader.setDownloadResource(StaticDownloadHandler.createResource(ui, pFileHandle, StaticDownloadHandler.TYPE_OPEN)); } else if (isIOSDevice()) { saveFileHandle(pFileHandle, null); } else { VaadinStreamResource resource = new VaadinStreamResource(pFileHandle, true); if (pBounds != null) { ui.getPage().open(resource, pTarget, pBounds.getWidth(), pBounds.getHeight(), BorderStyle.DEFAULT); } else { ui.getPage().open(resource, pTarget, true); } } } /** * {@inheritDoc} */ public void showFileHandle(IFileHandle pFileHandle) throws Throwable { showFileHandle(pFileHandle, null, "_blank"); } /** * {@inheritDoc} */ @SuppressWarnings("deprecation") public void saveFileHandle(final IFileHandle pFileHandle, String pTitle) throws Throwable { if (downloader != null) { if (isAndroidDevice()) { downloader.setDownloadResource(StaticDownloadHandler.createResource(ui, pFileHandle, StaticDownloadHandler.TYPE_SAVE)); } else { downloader.setDownloadResource(new VaadinStreamResource(pFileHandle, false)); } } //#1632 else if (isServletMode() && isMobileDevice()) { if (isIOSDevice() && !((VaadinServletService)VaadinService.getCurrent()).isPreserveUIOnRefresh()) { final Window win = new Window(StringUtil.isEmpty(pTitle) ? uilauncher.translate("Options") : uilauncher.translate(pTitle)); FileDownloader down = new FileDownloader(StaticDownloadHandler.createResource(ui, pFileHandle, StaticDownloadHandler.TYPE_SAVE)); ClickListener lisCloseWindow = new ClickListener() { @Override public void buttonClick(ClickEvent event) { win.close(); } }; Button butContinue = new Button(uilauncher.translate("Continue")); butContinue.addStyleName("continue"); butContinue.addClickListener(lisCloseWindow); butContinue.setWidth("100%"); down.extend(butContinue); Button butExit = new Button(uilauncher.translate("Cancel")); butExit.addStyleName("cancel"); butExit.addClickListener(lisCloseWindow); butExit.setWidth("100%"); VerticalLayout vlay = new VerticalLayout(); vlay.setSpacing(true); vlay.addStyleName("optionbuttons"); vlay.setMargin(true); vlay.setSizeFull(); vlay.addComponent(butContinue); vlay.addComponent(butExit); win.addStyleName("save"); win.setClosable(false); win.setDraggable(false); win.setResizable(false); win.setModal(true); win.setContent(vlay); win.center(); win.setWidth(150, Unit.PIXELS); win.setHeight(170, Unit.PIXELS); ui.addWindow(win); } else { requestHandler.fileHandle = pFileHandle; // Starts a request and so the handleRequest from the VaadinRequestHandler is called. ui.getPage().setLocation(getParameter(PARAM_REQUESTURI)); } } else { ui.getPage().open(new VaadinStreamResource(pFileHandle, false), "_blank", true); } } /** * {@inheritDoc} */ public void getFileHandle(final IFileHandleReceiver pFileHandleReceiver, String pTitle) throws Throwable { final Window window = new Window(pTitle == null ? "" : uilauncher.translate(pTitle)); window.setModal(true); window.addStyleName("upload"); window.setResizable(false); final ProgressBar progressBar = new ProgressBar(); progressBar.setWidth("100%"); progressBar.setVisible(false); progressBar.setIndeterminate(false); VerticalLayout layout = new VerticalLayout(); layout.setSpacing(true); final Upload upload = new Upload(); upload.setReceiver(new UploadReceiver()); if (!ui.getPushConfiguration().getPushMode().isEnabled()) // Set PollInterval if no push mode is set. { ui.setPollInterval(500); } window.addCloseListener(new CloseListener() { @Override public void windowClose(CloseEvent pEvent) { // Disable manual polling on window closing if (!ui.getPushConfiguration().getPushMode().isEnabled()) { performInvokeLater(); ui.setPollInterval(-1); } } }); upload.addStartedListener(new StartedListener() { public void uploadStarted(StartedEvent pEvent) { ui.access(new Runnable() { @Override public void run() { progressBar.setValue(0.0f); progressBar.setVisible(true); if (ui.getPushConfiguration().getPushMode().isEnabled()) { ui.push(); // Is needed because when push mode is manual } } }); } }); upload.addProgressListener(new ProgressListener() { public void updateProgress(final long readBytes, final long contentLength) { float newValue = readBytes / (float)contentLength; if ((newValue - progressBar.getValue()) >= 0.05f || readBytes >= contentLength) { ui.access(new Runnable() { @Override public void run() { progressBar.setValue(newValue); if (ui.getPushConfiguration().getPushMode().isEnabled()) { ui.push(); // Is needed because when push mode is manual } } }); } } }); upload.addSucceededListener(new SucceededListener() { public void uploadSucceeded(SucceededEvent pEvent) { if (!ui.getPushConfiguration().getPushMode().isEnabled()) { performInvokeLater(); ui.setPollInterval(-1); } } }); upload.addFailedListener(new Upload.FailedListener() { public void uploadFailed(FailedEvent pEvent) { try { ((UploadReceiver)upload.getReceiver()).delete(); } finally { if (!ui.getPushConfiguration().getPushMode().isEnabled()) { performInvokeLater(); ui.setPollInterval(-1); } } } }); upload.addFinishedListener(new FinishedListener() { public void uploadFinished(FinishedEvent pEvent) { if (!ui.getPushConfiguration().getPushMode().isEnabled()) { performInvokeLater(); ui.setPollInterval(-1); } UploadReceiver receiver = (UploadReceiver)upload.getReceiver(); InputStream inputStream = null; try { receiver.free(); //avoid multiple calls (possible if an error occurs) if (receiver.uploadFile != null) { inputStream = new FileInputStream(receiver.uploadFile); pFileHandleReceiver.receiveFileHandle(new FileHandle(pEvent.getFilename(), inputStream)); } } catch (Throwable th) { Throwable thWrapped = EventHandler.getWrappedExceptionAllowSilent(th); if (!(thWrapped instanceof SilentAbortException)) { ExceptionHandler.raise(thWrapped); } else { LoggerFactory.getInstance(VaadinUI.class).debug(th); } } finally { window.close(); if (inputStream != null) { try { inputStream.close(); } catch (Exception e) { //nothing to be done } } receiver.delete(); } } }); upload.setButtonCaption(uilauncher.translate("Upload")); upload.setWidth(100, Unit.PERCENTAGE); //NO additional caption needed inside the window //upload.setCaption(uilauncher.translate("Please choose the file:")); layout.setWidth(100, Unit.PERCENTAGE); layout.addComponent(upload); layout.addComponent(progressBar); window.setContent(layout); layout.setMargin(true); ui.addWindow(window); } /** * {@inheritDoc} */ public void cancelPendingThreads() { } /** * {@inheritDoc} */ public void setRegistryKey(String pKey, String pValue) { if (chtRegistry == null) { chtRegistry = new ChangedHashtable(); } String sName = LauncherUtil.getRegistryApplicationName(this); if (pValue == null) { chtRegistry.remove(sName + "." + pKey); if (chtRegistry.size() == 0) { chtRegistry = null; } } else { chtRegistry.put(sName + "." + pKey, pValue); } } /** * {@inheritDoc} */ public String getRegistryKey(String pKey) { if (chtRegistry == null) { return null; } String sName = LauncherUtil.getRegistryApplicationName(this); return chtRegistry.get(sName + "." + pKey); } /** * {@inheritDoc} */ public String getEnvironmentName() { return ILauncher.ENVIRONMENT_WEB + ":vaadin"; } /** * {@inheritDoc} */ public IApplication getApplication() { return application; } /** * {@inheritDoc} */ public Locale getLocale() { return locale; } /** * {@inheritDoc} */ public void setLocale(Locale pLocale) { locale = pLocale; LocaleUtil.setThreadDefault(locale); } /** * {@inheritDoc} */ public TimeZone getTimeZone() { return timeZone; } /** * {@inheritDoc} */ public void setTimeZone(TimeZone pTimeZone) { timeZone = pTimeZone; TimeZoneUtil.setThreadDefault(timeZone); } //IEXCEPTIONLISTENER /** * {@inheritDoc} */ public void handleException(Throwable pThrowable) { VaadinFactory.showError(ui, pThrowable); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Overwritten methods //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * {@inheritDoc} */ @Override public void setLayout(ILayout pLayout) { if (uilauncher != null) { super.setLayout(pLayout); } } /** * {@inheritDoc} */ @Override public void addToVaadin(IComponent pComponent, Object pConstraints, int pIndex) { if (uilauncher != null) { getRootPane().addComponentToContent(pComponent, pConstraints, pIndex); } } /** * {@inheritDoc} */ @Override public void removeFromVaadin(IComponent pComponent) { if (uilauncher != null) { getRootPane().removeComponentFromContent(pComponent); } } /** * {@inheritDoc} */ @Override public void dispose() { VaadinSession session = ui.getSession(); if (session != null) { session.removeRequestHandler(requestHandler); } if (windowResizeListenerRegistration != null) { windowResizeListenerRegistration.remove(); } if (downloader != null) { downloader.remove(); } if (application != null) { try { application.notifyDestroy(); } catch (Exception e) { //force closing the application LoggerFactory.getInstance(VaadinUI.class).info("Forced application destroy failed", e); } } try { VaadinFactory factory = ((VaadinFactory)getFactory()); //possible if init factory fails if (factory != null) { factory.destroyThreads(); } } finally { super.dispose(); } } /** * {@inheritDoc} */ @Override public void setTitle(String pTitle) { //e.g. don't change the title in portlet mode if (VaadinUI.isServletMode()) { super.setTitle(pTitle); } } /** * {@inheritDoc} */ @Override public IDimension getSize() { Page page = ui.getPage(); if (page != null) { int iWidth = page.getBrowserWindowWidth(); int iHeight = page.getBrowserWindowHeight(); if (iWidth > 0 && iHeight > 0) { return new VaadinDimension(iWidth, iHeight); } } return super.getSize(); } /** * {@inheritDoc} */ @Override public IRectangle getBounds() { Page page = ui.getPage(); if (page != null) { if (page != null) { int iWidth = page.getBrowserWindowWidth(); int iHeight = page.getBrowserWindowHeight(); if (iWidth > 0 && iHeight > 0) { return new VaadinRectangle(0, 0, iWidth, iHeight); } } } return super.getBounds(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // User-defined methods //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * Loads and merges the application configuration with current values. New values will be added and existing * values won't be replaced. * * @param pConfig the resource path of the application configuration */ protected void mergeConfiguration(String pConfig) { String sConfig = pConfig; //the configuration can be configured via an URL Parameter if (sConfig == null) { sConfig = "application.xml"; } try { InputStream isConfig = ResourceUtil.getResourceAsStream(ui.getApplicationClassLoader(), sConfig); if (isConfig != null) { try { XmlWorker xmw = new XmlWorker(); XmlNode xmnAppConfig = xmw.read(isConfig); if (xmnAppConfig != null) { List liNodes = xmnAppConfig.getNode(CONFIG_ROOT_NODE).getNodes(); String sKey; for (XmlNode xmnSub : liNodes) { sKey = xmnSub.getName(); //don't overwrite parameters, configured via URL or Deployment descriptor!!! if (!hmpParams.containsKey(sKey)) { hmpParams.put(sKey, xmnSub.getValue()); } } } } finally { CommonUtil.close(isConfig); } } } catch (Exception e) { LoggerFactory.getInstance(VaadinUI.class).error("Configuration load error!", e); } } /** * Gets a list of all registry key/value pairs which have changed since last access. * * @return the list of changed key/value pairs or null if no changes are available */ List> getRegistryChanges() { if (chtRegistry != null) { return chtRegistry.getChanges(); } else { return null; } } /** * Resets the internal instances. */ protected void resetInstances() { if (downloader != null) { downloader.setDownloadResource(null); } requestHandler.fileHandle = null; } /** * Performs invokeLater without session locking. */ private void performInvokeLater() { IFactory factory = getFactory(); if (factory != null) { ((VaadinFactory)factory).performInvokeLater(); } } /** * Gets whether the client is an android device. * * @return true if android device is used, false otherwise */ private boolean isAndroidDevice() { return "true".equals(hmpParams.get(PROP_ANDROID)); } /** * Gets whether the client is an iOS device. * * @return true if iOS device is used, false otherwise */ private boolean isIOSDevice() { return "true".equals(hmpParams.get(PROP_IOS)); } /** * Gets whether the client is a mobile device. * * @return true if a mobile device is used, false otherwise */ private boolean isMobileDevice() { return "true".equals(hmpParams.get(PROP_MOBILE)); } } // VaadinUILauncher /** * Handles the upload of a file. * * @author Stefan Wurm */ private static final class VaadinRequestHandler implements RequestHandler { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class members //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** the file handle. **/ private IFileHandle fileHandle = null; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Interface implementation //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * {@inheritDoc} */ public boolean handleRequest(VaadinSession pSession, VaadinRequest pRequest, VaadinResponse pResponse) throws IOException { if (fileHandle != null) { try { final DownloadStream stream = new DownloadStream(fileHandle.getInputStream(), "", fileHandle.getFileName()); if (stream.getParameter("Content-Disposition") == null) { // Content-Disposition: attachment generally forces download stream.setParameter("Content-Disposition", "attachment; filename=\"" + stream.getFileName() + "\""); stream.setContentType("application/octet-stream;charset=UTF-8"); } stream.writeResponse(pRequest, pResponse); fileHandle = null; return true; // We wrote a response } finally { fileHandle = null; } } else { return false; } } } // VaadinRequestHandler /** * Receives an Upload. * * @author Stefan Wurm */ private static final class UploadReceiver implements Upload.Receiver { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class members //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** The uploaded file. **/ private File uploadFile = null; /** The file output stream. */ private FileOutputStream fos = null; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Interface implementation //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * {@inheritDoc} */ public OutputStream receiveUpload(String pFileName, String pMimeType) { try { String sExt = FileUtil.getExtension(pFileName); if (StringUtil.isEmpty(sExt)) { sExt = null; } uploadFile = java.io.File.createTempFile("upload_" + FileUtil.getName(pFileName), sExt); fos = new FileOutputStream(uploadFile); } catch (IOException e) { ExceptionHandler.raise(e); return null; } return fos; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // User-defined methods //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * Deletes the cached file. */ public void delete() { free(); if (uploadFile != null) { if (!uploadFile.delete()) { uploadFile.deleteOnExit(); } uploadFile = null; } } /** * Frees all used resources. */ public void free() { if (fos != null) { try { fos.close(); } catch (Exception e) { //nothing to be done } finally { fos = null; } } } } // UploadReceiver /** * The ApplicationConfig is the global configuration for an application. * It contains startup information. * * @author Ren? Jahn */ public final class ApplicationConfig { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class members //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** the main class name. */ private String main; /** the path to the configuration file. */ private String config; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Initialization //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * Creates a new instance of ApplicationConfig. * * @param pMain the main class name * @param pConfig the path to the configuration file */ public ApplicationConfig(String pMain, String pConfig) { main = pMain; config = pConfig; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // User-defined methods //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * Gets the main class name. * * @return the class name */ public String getClassName() { return main; } /** * Gets the path to the configuration file. * * @return the config path */ public String getConfigPath() { return config; } } // ApplicationConfig /** * The InternalConnectorTracker stores whether the response was already written. * * @author Ren? Jahn */ public static class InternalConnectorTracker extends ConnectorTracker { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class members //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** the UI. */ private VaadinUI ui; /** whether invoke later was executed. */ private boolean bExecuted = false; /** whether performInvokeLater should be ignored. */ private boolean bIgnore = false; /** whether we should unregister the UI. */ private boolean bUnregisterUI = false; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Initialization //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * Creates a new instance of InternalConnectorTracker for the given UI. * * @param pUI the connected UI */ public InternalConnectorTracker(VaadinUI pUI) { super(pUI); ui = pUI; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Overwritten methods //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public Collection getDirtyConnectors() { if (!bIgnore && !isWritingResponse() && !bExecuted) { if (ui.launcher != null) { VaadinFactory fact = ui.launcher.getFactory(); if (fact != null) { ui.executePostConnectorTasks(); fact.performInvokeLater(); bExecuted = true; } } ui.writeCookies(); } return super.getDirtyConnectors(); } @Override public boolean hasDirtyConnectors() { //don't perform invokeLater bIgnore = true; try { return super.hasDirtyConnectors(); } finally { bIgnore = false; } } @Override public void setWritingResponse(boolean pWritingResponse) { //we need the factory in any case, because LegacyUidlWriter via push is out of our before/after mechanism if (pWritingResponse) { if (UIFactoryManager.getFactory() == null) { bUnregisterUI = true; ui.notifyBeforeUI(); } } else if (bUnregisterUI) { //only unregister if UI was registered from this tracker bUnregisterUI = false; ui.notifyAfterUI(); } super.setWritingResponse(pWritingResponse); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // User-defined methods //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * Sets executed flag. * * @param pExecuted false to reset execution */ public void setExecuted(boolean pExecuted) { bExecuted = pExecuted; } /** * Gets whether invoke later was executed. * * @return true if it was executed, false otherwise */ public boolean isExecuted() { return bExecuted; } } // InternalConnectorTracker } // VaadinUI




© 2015 - 2025 Weber Informatics LLC | Privacy Policy