diff options
author | Johannes Dahlström <johannesd@vaadin.com> | 2012-08-17 13:32:54 +0300 |
---|---|---|
committer | Johannes Dahlström <johannesd@vaadin.com> | 2012-08-17 13:32:54 +0300 |
commit | 47a0326c2fb2d6d8621e7a6fbfa2f011a48e15a4 (patch) | |
tree | 416685c3912f716eb09497cc7cce071786fe2d12 /src/com/vaadin/terminal/gwt/server | |
parent | 8e3aa0a9823556896f1af00599c3e79ca2ce2e01 (diff) | |
parent | 9bdbd7efbb7fa599910dc85182968334e4dced78 (diff) | |
download | vaadin-framework-47a0326c2fb2d6d8621e7a6fbfa2f011a48e15a4.tar.gz vaadin-framework-47a0326c2fb2d6d8621e7a6fbfa2f011a48e15a4.zip |
Merge branch 'master' into root-cleanup
Conflicts:
server/src/com/vaadin/terminal/DeploymentConfiguration.java
server/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
server/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
server/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java
Diffstat (limited to 'src/com/vaadin/terminal/gwt/server')
55 files changed, 0 insertions, 13487 deletions
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java deleted file mode 100644 index bfd35fd034..0000000000 --- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java +++ /dev/null @@ -1,1046 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.security.GeneralSecurityException; -import java.util.Enumeration; -import java.util.Locale; -import java.util.Map; -import java.util.Properties; -import java.util.logging.Logger; - -import javax.portlet.ActionRequest; -import javax.portlet.ActionResponse; -import javax.portlet.EventRequest; -import javax.portlet.EventResponse; -import javax.portlet.GenericPortlet; -import javax.portlet.PortletConfig; -import javax.portlet.PortletContext; -import javax.portlet.PortletException; -import javax.portlet.PortletRequest; -import javax.portlet.PortletResponse; -import javax.portlet.PortletSession; -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; -import javax.portlet.ResourceRequest; -import javax.portlet.ResourceResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; -import javax.servlet.http.HttpServletResponse; - -import com.liferay.portal.kernel.util.PortalClassInvoker; -import com.liferay.portal.kernel.util.PropsUtil; -import com.vaadin.Application; -import com.vaadin.Application.ApplicationStartEvent; -import com.vaadin.Application.SystemMessages; -import com.vaadin.RootRequiresMoreInformationException; -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.Terminal; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.WrappedResponse; -import com.vaadin.terminal.gwt.server.AbstractCommunicationManager.Callback; -import com.vaadin.ui.Root; - -/** - * Portlet 2.0 base class. This replaces the servlet in servlet/portlet 1.0 - * deployments and handles various portlet requests from the browser. - * - * TODO Document me! - * - * @author peholmst - */ -public abstract class AbstractApplicationPortlet extends GenericPortlet - implements Constants { - - public static final String RESOURCE_URL_ID = "APP"; - - public static class WrappedHttpAndPortletRequest extends - WrappedPortletRequest { - - public WrappedHttpAndPortletRequest(PortletRequest request, - HttpServletRequest originalRequest, - DeploymentConfiguration deploymentConfiguration) { - super(request, deploymentConfiguration); - this.originalRequest = originalRequest; - } - - private final HttpServletRequest originalRequest; - - @Override - public String getParameter(String name) { - String parameter = super.getParameter(name); - if (parameter == null) { - parameter = originalRequest.getParameter(name); - } - return parameter; - } - - @Override - public String getRemoteAddr() { - return originalRequest.getRemoteAddr(); - } - - @Override - public String getHeader(String name) { - String header = super.getHeader(name); - if (header == null) { - header = originalRequest.getHeader(name); - } - return header; - } - - @Override - public Map<String, String[]> getParameterMap() { - Map<String, String[]> parameterMap = super.getParameterMap(); - if (parameterMap == null) { - parameterMap = originalRequest.getParameterMap(); - } - return parameterMap; - } - } - - public static class WrappedGateinRequest extends - WrappedHttpAndPortletRequest { - public WrappedGateinRequest(PortletRequest request, - DeploymentConfiguration deploymentConfiguration) { - super(request, getOriginalRequest(request), deploymentConfiguration); - } - - private static final HttpServletRequest getOriginalRequest( - PortletRequest request) { - try { - Method getRealReq = request.getClass().getMethod( - "getRealRequest"); - HttpServletRequestWrapper origRequest = (HttpServletRequestWrapper) getRealReq - .invoke(request); - return origRequest; - } catch (Exception e) { - throw new IllegalStateException("GateIn request not detected", - e); - } - } - } - - public static class WrappedLiferayRequest extends - WrappedHttpAndPortletRequest { - - public WrappedLiferayRequest(PortletRequest request, - DeploymentConfiguration deploymentConfiguration) { - super(request, getOriginalRequest(request), deploymentConfiguration); - } - - @Override - public String getPortalProperty(String name) { - return PropsUtil.get(name); - } - - private static HttpServletRequest getOriginalRequest( - PortletRequest request) { - try { - // httpRequest = PortalUtil.getHttpServletRequest(request); - HttpServletRequest httpRequest = (HttpServletRequest) PortalClassInvoker - .invoke("com.liferay.portal.util.PortalUtil", - "getHttpServletRequest", request); - - // httpRequest = - // PortalUtil.getOriginalServletRequest(httpRequest); - httpRequest = (HttpServletRequest) PortalClassInvoker.invoke( - "com.liferay.portal.util.PortalUtil", - "getOriginalServletRequest", httpRequest); - return httpRequest; - } catch (Exception e) { - throw new IllegalStateException("Liferay request not detected", - e); - } - } - - } - - public static class AbstractApplicationPortletWrapper implements Callback { - - private final AbstractApplicationPortlet portlet; - - public AbstractApplicationPortletWrapper( - AbstractApplicationPortlet portlet) { - this.portlet = portlet; - } - - @Override - public void criticalNotification(WrappedRequest request, - WrappedResponse response, String cap, String msg, - String details, String outOfSyncURL) throws IOException { - portlet.criticalNotification(WrappedPortletRequest.cast(request), - (WrappedPortletResponse) response, cap, msg, details, - outOfSyncURL); - } - } - - /** - * This portlet parameter is used to add styles to the main element. E.g - * "height:500px" generates a style="height:500px" to the main element. - */ - public static final String PORTLET_PARAMETER_STYLE = "style"; - - /** - * This portal parameter is used to define the name of the Vaadin theme that - * is used for all Vaadin applications in the portal. - */ - public static final String PORTAL_PARAMETER_VAADIN_THEME = "vaadin.theme"; - - public static final String WRITE_AJAX_PAGE_SCRIPT_WIDGETSET_SHOULD_WRITE = "writeAjaxPageScriptWidgetsetShouldWrite"; - - // TODO some parts could be shared with AbstractApplicationServlet - - // TODO Can we close the application when the portlet is removed? Do we know - // when the portlet is removed? - - private boolean productionMode = false; - - private DeploymentConfiguration deploymentConfiguration = new AbstractDeploymentConfiguration( - getClass()) { - @Override - public String getConfiguredWidgetset(WrappedRequest request) { - - String widgetset = getApplicationOrSystemProperty( - PARAMETER_WIDGETSET, null); - - if (widgetset == null) { - // If no widgetset defined for the application, check the - // portal - // property - widgetset = WrappedPortletRequest.cast(request) - .getPortalProperty(PORTAL_PARAMETER_VAADIN_WIDGETSET); - } - - if (widgetset == null) { - // If no widgetset defined for the portal, use the default - widgetset = DEFAULT_WIDGETSET; - } - - return widgetset; - } - - @Override - public String getConfiguredTheme(WrappedRequest request) { - - // is the default theme defined by the portal? - String themeName = WrappedPortletRequest.cast(request) - .getPortalProperty(Constants.PORTAL_PARAMETER_VAADIN_THEME); - - if (themeName == null) { - // no, using the default theme defined by Vaadin - themeName = DEFAULT_THEME_NAME; - } - - return themeName; - } - - @Override - public boolean isStandalone(WrappedRequest request) { - return false; - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.terminal.DeploymentConfiguration#getStaticFileLocation - * (com.vaadin.terminal.WrappedRequest) - * - * Return the URL from where static files, e.g. the widgetset and the - * theme, are served. In a standard configuration the VAADIN folder - * inside the returned folder is what is used for widgetsets and themes. - * - * @return The location of static resources (inside which there should - * be a VAADIN directory). Does not end with a slash (/). - */ - - @Override - public String getStaticFileLocation(WrappedRequest request) { - String staticFileLocation = WrappedPortletRequest.cast(request) - .getPortalProperty( - Constants.PORTAL_PARAMETER_VAADIN_RESOURCE_PATH); - if (staticFileLocation != null) { - // remove trailing slash if any - while (staticFileLocation.endsWith(".")) { - staticFileLocation = staticFileLocation.substring(0, - staticFileLocation.length() - 1); - } - return staticFileLocation; - } else { - // default for Liferay - return "/html"; - } - } - - @Override - public String getMimeType(String resourceName) { - return getPortletContext().getMimeType(resourceName); - } - }; - - private final VaadinContext vaadinContext = new VaadinContext( - getDeploymentConfiguration()); - - @Override - public void init(PortletConfig config) throws PortletException { - super.init(config); - Properties applicationProperties = getDeploymentConfiguration() - .getInitParameters(); - - // Read default parameters from the context - final PortletContext context = config.getPortletContext(); - for (final Enumeration<String> e = context.getInitParameterNames(); e - .hasMoreElements();) { - final String name = e.nextElement(); - applicationProperties.setProperty(name, - context.getInitParameter(name)); - } - - // Override with application settings from portlet.xml - for (final Enumeration<String> e = config.getInitParameterNames(); e - .hasMoreElements();) { - final String name = e.nextElement(); - applicationProperties.setProperty(name, - config.getInitParameter(name)); - } - - vaadinContext.init(); - } - - @Override - public void destroy() { - super.destroy(); - - vaadinContext.destroy(); - } - - protected enum RequestType { - FILE_UPLOAD, UIDL, RENDER, STATIC_FILE, APPLICATION_RESOURCE, DUMMY, EVENT, ACTION, UNKNOWN, BROWSER_DETAILS, CONNECTOR_RESOURCE; - } - - protected RequestType getRequestType(WrappedPortletRequest wrappedRequest) { - PortletRequest request = wrappedRequest.getPortletRequest(); - if (request instanceof RenderRequest) { - return RequestType.RENDER; - } else if (request instanceof ResourceRequest) { - ResourceRequest resourceRequest = (ResourceRequest) request; - if (ServletPortletHelper.isUIDLRequest(wrappedRequest)) { - return RequestType.UIDL; - } else if (isBrowserDetailsRequest(resourceRequest)) { - return RequestType.BROWSER_DETAILS; - } else if (ServletPortletHelper.isFileUploadRequest(wrappedRequest)) { - return RequestType.FILE_UPLOAD; - } else if (ServletPortletHelper - .isConnectorResourceRequest(wrappedRequest)) { - return RequestType.CONNECTOR_RESOURCE; - } else if (ServletPortletHelper - .isApplicationResourceRequest(wrappedRequest)) { - return RequestType.APPLICATION_RESOURCE; - } else if (isDummyRequest(resourceRequest)) { - return RequestType.DUMMY; - } else { - return RequestType.STATIC_FILE; - } - } else if (request instanceof ActionRequest) { - return RequestType.ACTION; - } else if (request instanceof EventRequest) { - return RequestType.EVENT; - } - return RequestType.UNKNOWN; - } - - private boolean isBrowserDetailsRequest(ResourceRequest request) { - return request.getResourceID() != null - && request.getResourceID().equals("browserDetails"); - } - - private boolean isDummyRequest(ResourceRequest request) { - return request.getResourceID() != null - && request.getResourceID().equals("DUMMY"); - } - - /** - * Returns true if the servlet is running in production mode. Production - * mode disables all debug facilities. - * - * @return true if in production mode, false if in debug mode - */ - public boolean isProductionMode() { - return productionMode; - } - - protected void handleRequest(PortletRequest request, - PortletResponse response) throws PortletException, IOException { - RequestTimer requestTimer = new RequestTimer(); - requestTimer.start(); - - AbstractApplicationPortletWrapper portletWrapper = new AbstractApplicationPortletWrapper( - this); - - WrappedPortletRequest wrappedRequest = createWrappedRequest(request); - - WrappedPortletResponse wrappedResponse = new WrappedPortletResponse( - response, getDeploymentConfiguration()); - - RequestType requestType = getRequestType(wrappedRequest); - - if (requestType == RequestType.UNKNOWN) { - handleUnknownRequest(request, response); - } else if (requestType == RequestType.DUMMY) { - /* - * This dummy page is used by action responses to redirect to, in - * order to prevent the boot strap code from being rendered into - * strange places such as iframes. - */ - ((ResourceResponse) response).setContentType("text/html"); - final OutputStream out = ((ResourceResponse) response) - .getPortletOutputStream(); - final PrintWriter outWriter = new PrintWriter(new BufferedWriter( - new OutputStreamWriter(out, "UTF-8"))); - outWriter.print("<html><body>dummy page</body></html>"); - outWriter.close(); - } else if (requestType == RequestType.STATIC_FILE) { - serveStaticResources((ResourceRequest) request, - (ResourceResponse) response); - } else { - Application application = null; - boolean transactionStarted = false; - boolean requestStarted = false; - - try { - // TODO What about PARAM_UNLOADBURST & redirectToApplication?? - - /* Find out which application this request is related to */ - application = findApplicationInstance(wrappedRequest, - requestType); - if (application == null) { - return; - } - Application.setCurrent(application); - - /* - * Get or create an application context and an application - * manager for the session - */ - PortletApplicationContext2 applicationContext = getApplicationContext(request - .getPortletSession()); - applicationContext.setResponse(response); - applicationContext.setPortletConfig(getPortletConfig()); - - PortletCommunicationManager applicationManager = applicationContext - .getApplicationManager(application); - - if (requestType == RequestType.CONNECTOR_RESOURCE) { - applicationManager.serveConnectorResource(wrappedRequest, - wrappedResponse); - return; - } - - /* Update browser information from request */ - applicationContext.getBrowser().updateRequestDetails( - wrappedRequest); - - /* - * Call application requestStart before Application.init() is - * called (bypasses the limitation in TransactionListener) - */ - if (application instanceof PortletRequestListener) { - ((PortletRequestListener) application).onRequestStart( - request, response); - requestStarted = true; - } - - /* Start the newly created application */ - startApplication(request, application, applicationContext); - - /* - * Transaction starts. Call transaction listeners. Transaction - * end is called in the finally block below. - */ - applicationContext.startTransaction(application, request); - transactionStarted = true; - - /* Notify listeners */ - - // Finds the window within the application - Root root = null; - synchronized (application) { - if (application.isRunning()) { - switch (requestType) { - case RENDER: - case ACTION: - // Both action requests and render requests are ok - // without a Root as they render the initial HTML - // and then do a second request - try { - root = application - .getRootForRequest(wrappedRequest); - } catch (RootRequiresMoreInformationException e) { - // Ignore problem and continue without root - } - break; - case BROWSER_DETAILS: - // Should not try to find a root here as the - // combined request details might change the root - break; - case FILE_UPLOAD: - // no window - break; - case APPLICATION_RESOURCE: - // use main window - should not need any window - // root = application.getRoot(); - break; - default: - root = application - .getRootForRequest(wrappedRequest); - } - // if window not found, not a problem - use null - } - } - - // TODO Should this happen before or after the transaction - // starts? - if (request instanceof RenderRequest) { - applicationContext.firePortletRenderRequest(application, - root, (RenderRequest) request, - (RenderResponse) response); - } else if (request instanceof ActionRequest) { - applicationContext.firePortletActionRequest(application, - root, (ActionRequest) request, - (ActionResponse) response); - } else if (request instanceof EventRequest) { - applicationContext.firePortletEventRequest(application, - root, (EventRequest) request, - (EventResponse) response); - } else if (request instanceof ResourceRequest) { - applicationContext.firePortletResourceRequest(application, - root, (ResourceRequest) request, - (ResourceResponse) response); - } - - /* Handle the request */ - if (requestType == RequestType.FILE_UPLOAD) { - // Root is resolved in handleFileUpload by - // PortletCommunicationManager - applicationManager.handleFileUpload(application, - wrappedRequest, wrappedResponse); - return; - } else if (requestType == RequestType.BROWSER_DETAILS) { - applicationManager.handleBrowserDetailsRequest( - wrappedRequest, wrappedResponse, application); - return; - } else if (requestType == RequestType.UIDL) { - // Handles AJAX UIDL requests - applicationManager.handleUidlRequest(wrappedRequest, - wrappedResponse, portletWrapper, root); - return; - } else { - /* - * Removes the application if it has stopped - */ - if (!application.isRunning()) { - endApplication(request, response, application); - return; - } - - handleOtherRequest(wrappedRequest, wrappedResponse, - requestType, application, applicationContext, - applicationManager); - } - } catch (final SessionExpiredException e) { - // TODO Figure out a better way to deal with - // SessionExpiredExceptions - getLogger().finest("A user session has expired"); - } catch (final GeneralSecurityException e) { - // TODO Figure out a better way to deal with - // GeneralSecurityExceptions - getLogger() - .fine("General security exception, the security key was probably incorrect."); - } catch (final Throwable e) { - handleServiceException(wrappedRequest, wrappedResponse, - application, e); - } finally { - // Notifies transaction end - try { - if (transactionStarted) { - ((PortletApplicationContext2) application.getContext()) - .endTransaction(application, request); - } - } finally { - try { - if (requestStarted) { - ((PortletRequestListener) application) - .onRequestEnd(request, response); - - } - } finally { - Root.setCurrent(null); - Application.setCurrent(null); - - PortletSession session = request - .getPortletSession(false); - if (session != null) { - requestTimer.stop(getApplicationContext(session)); - } - } - } - } - } - } - - /** - * Wraps the request in a (possibly portal specific) wrapped portlet - * request. - * - * @param request - * The original PortletRequest - * @return A wrapped version of the PorletRequest - */ - protected WrappedPortletRequest createWrappedRequest(PortletRequest request) { - String portalInfo = request.getPortalContext().getPortalInfo() - .toLowerCase(); - if (portalInfo.contains("liferay")) { - return new WrappedLiferayRequest(request, - getDeploymentConfiguration()); - } else if (portalInfo.contains("gatein")) { - return new WrappedGateinRequest(request, - getDeploymentConfiguration()); - } else { - return new WrappedPortletRequest(request, - getDeploymentConfiguration()); - } - - } - - protected DeploymentConfiguration getDeploymentConfiguration() { - return deploymentConfiguration; - } - - private void handleUnknownRequest(PortletRequest request, - PortletResponse response) { - getLogger().warning("Unknown request type"); - } - - /** - * Handle a portlet request that is not for static files, UIDL or upload. - * Also render requests are handled here. - * - * This method is called after starting the application and calling portlet - * and transaction listeners. - * - * @param request - * @param response - * @param requestType - * @param application - * @param applicationContext - * @param applicationManager - * @throws PortletException - * @throws IOException - * @throws MalformedURLException - */ - private void handleOtherRequest(WrappedPortletRequest request, - WrappedResponse response, RequestType requestType, - Application application, - PortletApplicationContext2 applicationContext, - PortletCommunicationManager applicationManager) - throws PortletException, IOException, MalformedURLException { - if (requestType == RequestType.APPLICATION_RESOURCE - || requestType == RequestType.RENDER) { - if (!applicationManager.handleApplicationRequest(request, response)) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - "Not found"); - } - } else if (requestType == RequestType.EVENT) { - // nothing to do, listeners do all the work - } else if (requestType == RequestType.ACTION) { - // nothing to do, listeners do all the work - } else { - throw new IllegalStateException( - "handleRequest() without anything to do - should never happen!"); - } - } - - @Override - public void processEvent(EventRequest request, EventResponse response) - throws PortletException, IOException { - handleRequest(request, response); - } - - private void serveStaticResources(ResourceRequest request, - ResourceResponse response) throws IOException, PortletException { - final String resourceID = request.getResourceID(); - final PortletContext pc = getPortletContext(); - - InputStream is = pc.getResourceAsStream(resourceID); - if (is != null) { - final String mimetype = pc.getMimeType(resourceID); - if (mimetype != null) { - response.setContentType(mimetype); - } - final OutputStream os = response.getPortletOutputStream(); - final byte buffer[] = new byte[DEFAULT_BUFFER_SIZE]; - int bytes; - while ((bytes = is.read(buffer)) >= 0) { - os.write(buffer, 0, bytes); - } - } else { - getLogger().info( - "Requested resource [" + resourceID - + "] could not be found"); - response.setProperty(ResourceResponse.HTTP_STATUS_CODE, - Integer.toString(HttpServletResponse.SC_NOT_FOUND)); - } - } - - @Override - public void processAction(ActionRequest request, ActionResponse response) - throws PortletException, IOException { - handleRequest(request, response); - } - - @Override - protected void doDispatch(RenderRequest request, RenderResponse response) - throws PortletException, IOException { - try { - // try to let super handle - it'll call methods annotated for - // handling, the default doXYZ(), or throw if a handler for the mode - // is not found - super.doDispatch(request, response); - - } catch (PortletException e) { - if (e.getCause() == null) { - // No cause interpreted as 'unknown mode' - pass that trough - // so that the application can handle - handleRequest(request, response); - - } else { - // Something else failed, pass on - throw e; - } - } - } - - @Override - public void serveResource(ResourceRequest request, ResourceResponse response) - throws PortletException, IOException { - handleRequest(request, response); - } - - boolean requestCanCreateApplication(PortletRequest request, - RequestType requestType) { - if (requestType == RequestType.UIDL && isRepaintAll(request)) { - return true; - } else if (requestType == RequestType.RENDER) { - // In most cases the first request is a render request that renders - // the HTML fragment. This should create an application instance. - return true; - } else if (requestType == RequestType.EVENT) { - // A portlet can also be sent an event even though it has not been - // rendered, e.g. portlet on one page sends an event to a portlet on - // another page and then moves the user to that page. - return true; - } - return false; - } - - private boolean isRepaintAll(PortletRequest request) { - return (request.getParameter(URL_PARAMETER_REPAINT_ALL) != null) - && (request.getParameter(URL_PARAMETER_REPAINT_ALL).equals("1")); - } - - private void startApplication(PortletRequest request, - Application application, PortletApplicationContext2 context) - throws PortletException, MalformedURLException { - if (!application.isRunning()) { - Locale locale = request.getLocale(); - application.setLocale(locale); - // No application URL when running inside a portlet - application.start(new ApplicationStartEvent(null, - getDeploymentConfiguration(), context)); - } - } - - private void endApplication(PortletRequest request, - PortletResponse response, Application application) - throws IOException { - final PortletSession session = request.getPortletSession(); - if (session != null) { - getApplicationContext(session).removeApplication(application); - } - // Do not send any redirects when running inside a portlet. - } - - private Application findApplicationInstance( - WrappedPortletRequest wrappedRequest, RequestType requestType) - throws PortletException, SessionExpiredException, - MalformedURLException { - PortletRequest request = wrappedRequest.getPortletRequest(); - - boolean requestCanCreateApplication = requestCanCreateApplication( - request, requestType); - - /* Find an existing application for this request. */ - Application application = getExistingApplication(request, - requestCanCreateApplication); - - if (application != null) { - /* - * There is an existing application. We can use this as long as the - * user not specifically requested to close or restart it. - */ - - final boolean restartApplication = (wrappedRequest - .getParameter(URL_PARAMETER_RESTART_APPLICATION) != null); - final boolean closeApplication = (wrappedRequest - .getParameter(URL_PARAMETER_CLOSE_APPLICATION) != null); - - if (restartApplication) { - closeApplication(application, request.getPortletSession(false)); - return createApplication(request); - } else if (closeApplication) { - closeApplication(application, request.getPortletSession(false)); - return null; - } else { - return application; - } - } - - // No existing application was found - - if (requestCanCreateApplication) { - return createApplication(request); - } else { - throw new SessionExpiredException(); - } - } - - private void closeApplication(Application application, - PortletSession session) { - if (application == null) { - return; - } - - application.close(); - if (session != null) { - PortletApplicationContext2 context = getApplicationContext(session); - context.removeApplication(application); - } - } - - private Application createApplication(PortletRequest request) - throws PortletException, MalformedURLException { - Application newApplication = getNewApplication(request); - final PortletApplicationContext2 context = getApplicationContext(request - .getPortletSession()); - context.addApplication(newApplication, request.getWindowID()); - return newApplication; - } - - private Application getExistingApplication(PortletRequest request, - boolean allowSessionCreation) throws MalformedURLException, - SessionExpiredException { - - final PortletSession session = request - .getPortletSession(allowSessionCreation); - - if (session == null) { - throw new SessionExpiredException(); - } - - PortletApplicationContext2 context = getApplicationContext(session); - Application application = context.getApplicationForWindowId(request - .getWindowID()); - if (application == null) { - return null; - } - if (application.isRunning()) { - return application; - } - // application found but not running - context.removeApplication(application); - - return null; - } - - protected abstract Class<? extends Application> getApplicationClass() - throws ClassNotFoundException; - - protected Application getNewApplication(PortletRequest request) - throws PortletException { - try { - final Application application = getApplicationClass().newInstance(); - application.setRootPreserved(true); - return application; - } catch (final IllegalAccessException e) { - throw new PortletException("getNewApplication failed", e); - } catch (final InstantiationException e) { - throw new PortletException("getNewApplication failed", e); - } catch (final ClassNotFoundException e) { - throw new PortletException("getNewApplication failed", e); - } - } - - /** - * Get system messages from the current application class - * - * @return - */ - protected SystemMessages getSystemMessages() { - try { - Class<? extends Application> appCls = getApplicationClass(); - Method m = appCls.getMethod("getSystemMessages", (Class[]) null); - return (Application.SystemMessages) m.invoke(null, (Object[]) null); - } catch (ClassNotFoundException e) { - // This should never happen - throw new SystemMessageException(e); - } catch (SecurityException e) { - throw new SystemMessageException( - "Application.getSystemMessage() should be static public", e); - } catch (NoSuchMethodException e) { - // This is completely ok and should be silently ignored - } catch (IllegalArgumentException e) { - // This should never happen - throw new SystemMessageException(e); - } catch (IllegalAccessException e) { - throw new SystemMessageException( - "Application.getSystemMessage() should be static public", e); - } catch (InvocationTargetException e) { - // This should never happen - throw new SystemMessageException(e); - } - return Application.getSystemMessages(); - } - - private void handleServiceException(WrappedPortletRequest request, - WrappedPortletResponse response, Application application, - Throwable e) throws IOException, PortletException { - // TODO Check that this error handler is working when running inside a - // portlet - - // if this was an UIDL request, response UIDL back to client - if (getRequestType(request) == RequestType.UIDL) { - Application.SystemMessages ci = getSystemMessages(); - criticalNotification(request, response, - ci.getInternalErrorCaption(), ci.getInternalErrorMessage(), - null, ci.getInternalErrorURL()); - if (application != null) { - application.getErrorHandler() - .terminalError(new RequestError(e)); - } else { - throw new PortletException(e); - } - } else { - // Re-throw other exceptions - throw new PortletException(e); - } - - } - - @SuppressWarnings("serial") - public class RequestError implements Terminal.ErrorEvent, Serializable { - - private final Throwable throwable; - - public RequestError(Throwable throwable) { - this.throwable = throwable; - } - - @Override - public Throwable getThrowable() { - return throwable; - } - - } - - /** - * Send notification to client's application. Used to notify client of - * critical errors and session expiration due to long inactivity. Server has - * no knowledge of what application client refers to. - * - * @param request - * the Portlet request instance. - * @param response - * the Portlet response to write to. - * @param caption - * for the notification - * @param message - * for the notification - * @param details - * a detail message to show in addition to the passed message. - * Currently shown directly but could be hidden behind a details - * drop down. - * @param url - * url to load after message, null for current page - * @throws IOException - * if the writing failed due to input/output error. - */ - void criticalNotification(WrappedPortletRequest request, - WrappedPortletResponse response, String caption, String message, - String details, String url) throws IOException { - - // clients JS app is still running, but server application either - // no longer exists or it might fail to perform reasonably. - // send a notification to client's application and link how - // to "restart" application. - - if (caption != null) { - caption = "\"" + caption + "\""; - } - if (details != null) { - if (message == null) { - message = details; - } else { - message += "<br/><br/>" + details; - } - } - if (message != null) { - message = "\"" + message + "\""; - } - if (url != null) { - url = "\"" + url + "\""; - } - - // Set the response type - response.setContentType("application/json; charset=UTF-8"); - final OutputStream out = response.getOutputStream(); - final PrintWriter outWriter = new PrintWriter(new BufferedWriter( - new OutputStreamWriter(out, "UTF-8"))); - outWriter.print("for(;;);[{\"changes\":[], \"meta\" : {" - + "\"appError\": {" + "\"caption\":" + caption + "," - + "\"message\" : " + message + "," + "\"url\" : " + url - + "}}, \"resources\": {}, \"locales\":[]}]"); - outWriter.close(); - } - - /** - * - * Gets the application context for a PortletSession. If no context is - * currently stored in a session a new context is created and stored in the - * session. - * - * @param portletSession - * the portlet session. - * @return the application context for the session. - */ - protected PortletApplicationContext2 getApplicationContext( - PortletSession portletSession) { - return PortletApplicationContext2.getApplicationContext(portletSession); - } - - private static final Logger getLogger() { - return Logger.getLogger(AbstractApplicationPortlet.class.getName()); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java deleted file mode 100644 index 2ba19b0cf6..0000000000 --- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java +++ /dev/null @@ -1,1572 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.security.GeneralSecurityException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Locale; -import java.util.Properties; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import com.vaadin.Application; -import com.vaadin.Application.ApplicationStartEvent; -import com.vaadin.Application.SystemMessages; -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.Terminal; -import com.vaadin.terminal.ThemeResource; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.WrappedResponse; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.server.AbstractCommunicationManager.Callback; -import com.vaadin.ui.Root; - -/** - * Abstract implementation of the ApplicationServlet which handles all - * communication between the client and the server. - * - * It is possible to extend this class to provide own functionality but in most - * cases this is unnecessary. - * - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 6.0 - */ - -@SuppressWarnings("serial") -public abstract class AbstractApplicationServlet extends HttpServlet implements - Constants { - - private static class AbstractApplicationServletWrapper implements Callback { - - private final AbstractApplicationServlet servlet; - - public AbstractApplicationServletWrapper( - AbstractApplicationServlet servlet) { - this.servlet = servlet; - } - - @Override - public void criticalNotification(WrappedRequest request, - WrappedResponse response, String cap, String msg, - String details, String outOfSyncURL) throws IOException { - servlet.criticalNotification( - WrappedHttpServletRequest.cast(request), - ((WrappedHttpServletResponse) response), cap, msg, details, - outOfSyncURL); - } - } - - // TODO Move some (all?) of the constants to a separate interface (shared - // with portlet) - - private final String resourcePath = null; - - private DeploymentConfiguration deploymentConfiguration = new AbstractDeploymentConfiguration( - getClass()) { - - @Override - public String getStaticFileLocation(WrappedRequest request) { - HttpServletRequest servletRequest = WrappedHttpServletRequest - .cast(request); - return AbstractApplicationServlet.this - .getStaticFilesLocation(servletRequest); - } - - @Override - public String getConfiguredWidgetset(WrappedRequest request) { - return getApplicationOrSystemProperty( - AbstractApplicationServlet.PARAMETER_WIDGETSET, - AbstractApplicationServlet.DEFAULT_WIDGETSET); - } - - @Override - public String getConfiguredTheme(WrappedRequest request) { - // Use the default - return AbstractApplicationServlet.getDefaultTheme(); - } - - @Override - public boolean isStandalone(WrappedRequest request) { - return true; - } - - @Override - public String getMimeType(String resourceName) { - return getServletContext().getMimeType(resourceName); - } - }; - - private final VaadinContext vaadinContext = new VaadinContext( - getDeploymentConfiguration()); - - /** - * Called by the servlet container to indicate to a servlet that the servlet - * is being placed into service. - * - * @param servletConfig - * the object containing the servlet's configuration and - * initialization parameters - * @throws javax.servlet.ServletException - * if an exception has occurred that interferes with the - * servlet's normal operation. - */ - @Override - public void init(javax.servlet.ServletConfig servletConfig) - throws javax.servlet.ServletException { - super.init(servletConfig); - Properties applicationProperties = getDeploymentConfiguration() - .getInitParameters(); - - // Read default parameters from server.xml - final ServletContext context = servletConfig.getServletContext(); - for (final Enumeration<String> e = context.getInitParameterNames(); e - .hasMoreElements();) { - final String name = e.nextElement(); - applicationProperties.setProperty(name, - context.getInitParameter(name)); - } - - // Override with application config from web.xml - for (final Enumeration<String> e = servletConfig - .getInitParameterNames(); e.hasMoreElements();) { - final String name = e.nextElement(); - applicationProperties.setProperty(name, - servletConfig.getInitParameter(name)); - } - - vaadinContext.init(); - } - - @Override - public void destroy() { - super.destroy(); - - vaadinContext.destroy(); - } - - /** - * Returns true if the servlet is running in production mode. Production - * mode disables all debug facilities. - * - * @return true if in production mode, false if in debug mode - */ - public boolean isProductionMode() { - return getDeploymentConfiguration().isProductionMode(); - } - - /** - * Returns the number of seconds the browser should cache a file. Default is - * 1 hour (3600 s). - * - * @return The number of seconds files are cached in the browser - */ - public int getResourceCacheTime() { - return getDeploymentConfiguration().getResourceCacheTime(); - } - - /** - * Receives standard HTTP requests from the public service method and - * dispatches them. - * - * @param request - * the object that contains the request the client made of the - * servlet. - * @param response - * the object that contains the response the servlet returns to - * the client. - * @throws ServletException - * if an input or output error occurs while the servlet is - * handling the TRACE request. - * @throws IOException - * if the request for the TRACE cannot be handled. - */ - - @Override - protected void service(HttpServletRequest request, - HttpServletResponse response) throws ServletException, IOException { - service(createWrappedRequest(request), createWrappedResponse(response)); - } - - private void service(WrappedHttpServletRequest request, - WrappedHttpServletResponse response) throws ServletException, - IOException { - RequestTimer requestTimer = new RequestTimer(); - requestTimer.start(); - - AbstractApplicationServletWrapper servletWrapper = new AbstractApplicationServletWrapper( - this); - - RequestType requestType = getRequestType(request); - if (!ensureCookiesEnabled(requestType, request, response)) { - return; - } - - if (requestType == RequestType.STATIC_FILE) { - serveStaticResources(request, response); - return; - } - - Application application = null; - boolean transactionStarted = false; - boolean requestStarted = false; - - try { - // If a duplicate "close application" URL is received for an - // application that is not open, redirect to the application's main - // page. - // This is needed as e.g. Spring Security remembers the last - // URL from the application, which is the logout URL, and repeats - // it. - // We can tell apart a real onunload request from a repeated one - // based on the real one having content (at least the UIDL security - // key). - if (requestType == RequestType.UIDL - && request.getParameterMap().containsKey( - ApplicationConnection.PARAM_UNLOADBURST) - && request.getContentLength() < 1 - && getExistingApplication(request, false) == null) { - redirectToApplication(request, response); - return; - } - - // Find out which application this request is related to - application = findApplicationInstance(request, requestType); - if (application == null) { - return; - } - Application.setCurrent(application); - - /* - * Get or create a WebApplicationContext and an ApplicationManager - * for the session - */ - WebApplicationContext webApplicationContext = getApplicationContext(request - .getSession()); - CommunicationManager applicationManager = webApplicationContext - .getApplicationManager(application, this); - - if (requestType == RequestType.CONNECTOR_RESOURCE) { - applicationManager.serveConnectorResource(request, response); - return; - } - - /* Update browser information from the request */ - webApplicationContext.getBrowser().updateRequestDetails(request); - - /* - * Call application requestStart before Application.init() is called - * (bypasses the limitation in TransactionListener) - */ - if (application instanceof HttpServletRequestListener) { - ((HttpServletRequestListener) application).onRequestStart( - request, response); - requestStarted = true; - } - - // Start the application if it's newly created - startApplication(request, application, webApplicationContext); - - /* - * Transaction starts. Call transaction listeners. Transaction end - * is called in the finally block below. - */ - webApplicationContext.startTransaction(application, request); - transactionStarted = true; - - /* Handle the request */ - if (requestType == RequestType.FILE_UPLOAD) { - // Root is resolved in communication manager - applicationManager.handleFileUpload(application, request, - response); - return; - } else if (requestType == RequestType.UIDL) { - Root root = application.getRootForRequest(request); - if (root == null) { - throw new ServletException(ERROR_NO_ROOT_FOUND); - } - // Handles AJAX UIDL requests - applicationManager.handleUidlRequest(request, response, - servletWrapper, root); - return; - } else if (requestType == RequestType.BROWSER_DETAILS) { - // Browser details - not related to a specific root - applicationManager.handleBrowserDetailsRequest(request, - response, application); - return; - } - - // Removes application if it has stopped (maybe by thread or - // transactionlistener) - if (!application.isRunning()) { - endApplication(request, response, application); - return; - } - - if (applicationManager.handleApplicationRequest(request, response)) { - return; - } - // TODO Should return 404 error here and not do anything more - - } catch (final SessionExpiredException e) { - // Session has expired, notify user - handleServiceSessionExpired(request, response); - } catch (final GeneralSecurityException e) { - handleServiceSecurityException(request, response); - } catch (final Throwable e) { - handleServiceException(request, response, application, e); - } finally { - // Notifies transaction end - try { - if (transactionStarted) { - ((WebApplicationContext) application.getContext()) - .endTransaction(application, request); - - } - - } finally { - try { - if (requestStarted) { - ((HttpServletRequestListener) application) - .onRequestEnd(request, response); - } - } finally { - Root.setCurrent(null); - Application.setCurrent(null); - - HttpSession session = request.getSession(false); - if (session != null) { - requestTimer.stop(getApplicationContext(session)); - } - } - } - - } - } - - private WrappedHttpServletResponse createWrappedResponse( - HttpServletResponse response) { - WrappedHttpServletResponse wrappedResponse = new WrappedHttpServletResponse( - response, getDeploymentConfiguration()); - return wrappedResponse; - } - - /** - * Create a wrapped request for a http servlet request. This method can be - * overridden if the wrapped request should have special properties. - * - * @param request - * the original http servlet request - * @return a wrapped request for the original request - */ - protected WrappedHttpServletRequest createWrappedRequest( - HttpServletRequest request) { - return new WrappedHttpServletRequest(request, - getDeploymentConfiguration()); - } - - /** - * Gets a the deployment configuration for this servlet. - * - * @return the deployment configuration - */ - protected DeploymentConfiguration getDeploymentConfiguration() { - return deploymentConfiguration; - } - - /** - * Check that cookie support is enabled in the browser. Only checks UIDL - * requests. - * - * @param requestType - * Type of the request as returned by - * {@link #getRequestType(HttpServletRequest)} - * @param request - * The request from the browser - * @param response - * The response to which an error can be written - * @return false if cookies are disabled, true otherwise - * @throws IOException - */ - private boolean ensureCookiesEnabled(RequestType requestType, - WrappedHttpServletRequest request, - WrappedHttpServletResponse response) throws IOException { - if (requestType == RequestType.UIDL && !isRepaintAll(request)) { - // In all other but the first UIDL request a cookie should be - // returned by the browser. - // This can be removed if cookieless mode (#3228) is supported - if (request.getRequestedSessionId() == null) { - // User has cookies disabled - criticalNotification(request, response, getSystemMessages() - .getCookiesDisabledCaption(), getSystemMessages() - .getCookiesDisabledMessage(), null, getSystemMessages() - .getCookiesDisabledURL()); - return false; - } - } - return true; - } - - /** - * Send a notification to client's application. Used to notify client of - * critical errors, session expiration and more. Server has no knowledge of - * what application client refers to. - * - * @param request - * the HTTP request instance. - * @param response - * the HTTP response to write to. - * @param caption - * the notification caption - * @param message - * to notification body - * @param details - * a detail message to show in addition to the message. Currently - * shown directly below the message but could be hidden behind a - * details drop down in the future. Mainly used to give - * additional information not necessarily useful to the end user. - * @param url - * url to load when the message is dismissed. Null will reload - * the current page. - * @throws IOException - * if the writing failed due to input/output error. - */ - protected void criticalNotification(WrappedHttpServletRequest request, - HttpServletResponse response, String caption, String message, - String details, String url) throws IOException { - - if (ServletPortletHelper.isUIDLRequest(request)) { - - if (caption != null) { - caption = "\"" + JsonPaintTarget.escapeJSON(caption) + "\""; - } - if (details != null) { - if (message == null) { - message = details; - } else { - message += "<br/><br/>" + details; - } - } - - if (message != null) { - message = "\"" + JsonPaintTarget.escapeJSON(message) + "\""; - } - if (url != null) { - url = "\"" + JsonPaintTarget.escapeJSON(url) + "\""; - } - - String output = "for(;;);[{\"changes\":[], \"meta\" : {" - + "\"appError\": {" + "\"caption\":" + caption + "," - + "\"message\" : " + message + "," + "\"url\" : " + url - + "}}, \"resources\": {}, \"locales\":[]}]"; - writeResponse(response, "application/json; charset=UTF-8", output); - } else { - // Create an HTML reponse with the error - String output = ""; - - if (url != null) { - output += "<a href=\"" + url + "\">"; - } - if (caption != null) { - output += "<b>" + caption + "</b><br/>"; - } - if (message != null) { - output += message; - output += "<br/><br/>"; - } - - if (details != null) { - output += details; - output += "<br/><br/>"; - } - if (url != null) { - output += "</a>"; - } - writeResponse(response, "text/html; charset=UTF-8", output); - - } - - } - - /** - * Writes the response in {@code output} using the contentType given in - * {@code contentType} to the provided {@link HttpServletResponse} - * - * @param response - * @param contentType - * @param output - * Output to write (UTF-8 encoded) - * @throws IOException - */ - private void writeResponse(HttpServletResponse response, - String contentType, String output) throws IOException { - response.setContentType(contentType); - final ServletOutputStream out = response.getOutputStream(); - // Set the response type - final PrintWriter outWriter = new PrintWriter(new BufferedWriter( - new OutputStreamWriter(out, "UTF-8"))); - outWriter.print(output); - outWriter.flush(); - outWriter.close(); - out.flush(); - - } - - /** - * Returns the application instance to be used for the request. If an - * existing instance is not found a new one is created or null is returned - * to indicate that the application is not available. - * - * @param request - * @param requestType - * @return - * @throws MalformedURLException - * @throws IllegalAccessException - * @throws InstantiationException - * @throws ServletException - * @throws SessionExpiredException - */ - private Application findApplicationInstance(HttpServletRequest request, - RequestType requestType) throws MalformedURLException, - ServletException, SessionExpiredException { - - boolean requestCanCreateApplication = requestCanCreateApplication( - request, requestType); - - /* Find an existing application for this request. */ - Application application = getExistingApplication(request, - requestCanCreateApplication); - - if (application != null) { - /* - * There is an existing application. We can use this as long as the - * user not specifically requested to close or restart it. - */ - - final boolean restartApplication = (request - .getParameter(URL_PARAMETER_RESTART_APPLICATION) != null); - final boolean closeApplication = (request - .getParameter(URL_PARAMETER_CLOSE_APPLICATION) != null); - - if (restartApplication) { - closeApplication(application, request.getSession(false)); - return createApplication(request); - } else if (closeApplication) { - closeApplication(application, request.getSession(false)); - return null; - } else { - return application; - } - } - - // No existing application was found - - if (requestCanCreateApplication) { - /* - * If the request is such that it should create a new application if - * one as not found, we do that. - */ - return createApplication(request); - } else { - /* - * The application was not found and a new one should not be - * created. Assume the session has expired. - */ - throw new SessionExpiredException(); - } - - } - - /** - * Check if the request should create an application if an existing - * application is not found. - * - * @param request - * @param requestType - * @return true if an application should be created, false otherwise - */ - boolean requestCanCreateApplication(HttpServletRequest request, - RequestType requestType) { - if (requestType == RequestType.UIDL && isRepaintAll(request)) { - /* - * UIDL request contains valid repaintAll=1 event, the user probably - * wants to initiate a new application through a custom index.html - * without using the bootstrap page. - */ - return true; - - } else if (requestType == RequestType.OTHER) { - /* - * I.e URIs that are not application resources or static (theme) - * files. - */ - return true; - - } - - return false; - } - - /** - * Gets resource path using different implementations. Required to - * supporting different servlet container implementations (application - * servers). - * - * @param servletContext - * @param path - * the resource path. - * @return the resource path. - */ - protected static String getResourcePath(ServletContext servletContext, - String path) { - String resultPath = null; - resultPath = servletContext.getRealPath(path); - if (resultPath != null) { - return resultPath; - } else { - try { - final URL url = servletContext.getResource(path); - resultPath = url.getFile(); - } catch (final Exception e) { - // FIXME: Handle exception - getLogger().log(Level.INFO, - "Could not find resource path " + path, e); - } - } - return resultPath; - } - - /** - * Creates a new application and registers it into WebApplicationContext - * (aka session). This is not meant to be overridden. Override - * getNewApplication to create the application instance in a custom way. - * - * @param request - * @return - * @throws ServletException - * @throws MalformedURLException - */ - private Application createApplication(HttpServletRequest request) - throws ServletException, MalformedURLException { - Application newApplication = getNewApplication(request); - - final WebApplicationContext context = getApplicationContext(request - .getSession()); - context.addApplication(newApplication); - - return newApplication; - } - - private void handleServiceException(WrappedHttpServletRequest request, - WrappedHttpServletResponse response, Application application, - Throwable e) throws IOException, ServletException { - // if this was an UIDL request, response UIDL back to client - if (getRequestType(request) == RequestType.UIDL) { - Application.SystemMessages ci = getSystemMessages(); - criticalNotification(request, response, - ci.getInternalErrorCaption(), ci.getInternalErrorMessage(), - null, ci.getInternalErrorURL()); - if (application != null) { - application.getErrorHandler() - .terminalError(new RequestError(e)); - } else { - throw new ServletException(e); - } - } else { - // Re-throw other exceptions - throw new ServletException(e); - } - - } - - /** - * A helper method to strip away characters that might somehow be used for - * XSS attacs. Leaves at least alphanumeric characters intact. Also removes - * eg. ( and ), so values should be safe in javascript too. - * - * @param themeName - * @return - */ - protected static String stripSpecialChars(String themeName) { - StringBuilder sb = new StringBuilder(); - char[] charArray = themeName.toCharArray(); - for (int i = 0; i < charArray.length; i++) { - char c = charArray[i]; - if (!CHAR_BLACKLIST.contains(c)) { - sb.append(c); - } - } - return sb.toString(); - } - - private static final Collection<Character> CHAR_BLACKLIST = new HashSet<Character>( - Arrays.asList(new Character[] { '&', '"', '\'', '<', '>', '(', ')', - ';' })); - - /** - * Returns the default theme. Must never return null. - * - * @return - */ - public static String getDefaultTheme() { - return DEFAULT_THEME_NAME; - } - - void handleServiceSessionExpired(WrappedHttpServletRequest request, - WrappedHttpServletResponse response) throws IOException, - ServletException { - - if (isOnUnloadRequest(request)) { - /* - * Request was an unload request (e.g. window close event) and the - * client expects no response if it fails. - */ - return; - } - - try { - Application.SystemMessages ci = getSystemMessages(); - if (getRequestType(request) != RequestType.UIDL) { - // 'plain' http req - e.g. browser reload; - // just go ahead redirect the browser - response.sendRedirect(ci.getSessionExpiredURL()); - } else { - /* - * Invalidate session (weird to have session if we're saying - * that it's expired, and worse: portal integration will fail - * since the session is not created by the portal. - * - * Session must be invalidated before criticalNotification as it - * commits the response. - */ - request.getSession().invalidate(); - - // send uidl redirect - criticalNotification(request, response, - ci.getSessionExpiredCaption(), - ci.getSessionExpiredMessage(), null, - ci.getSessionExpiredURL()); - - } - } catch (SystemMessageException ee) { - throw new ServletException(ee); - } - - } - - private void handleServiceSecurityException( - WrappedHttpServletRequest request, - WrappedHttpServletResponse response) throws IOException, - ServletException { - if (isOnUnloadRequest(request)) { - /* - * Request was an unload request (e.g. window close event) and the - * client expects no response if it fails. - */ - return; - } - - try { - Application.SystemMessages ci = getSystemMessages(); - if (getRequestType(request) != RequestType.UIDL) { - // 'plain' http req - e.g. browser reload; - // just go ahead redirect the browser - response.sendRedirect(ci.getCommunicationErrorURL()); - } else { - // send uidl redirect - criticalNotification(request, response, - ci.getCommunicationErrorCaption(), - ci.getCommunicationErrorMessage(), - INVALID_SECURITY_KEY_MSG, ci.getCommunicationErrorURL()); - /* - * Invalidate session. Portal integration will fail otherwise - * since the session is not created by the portal. - */ - request.getSession().invalidate(); - } - } catch (SystemMessageException ee) { - throw new ServletException(ee); - } - - log("Invalid security key received from " + request.getRemoteHost()); - } - - /** - * Creates a new application for the given request. - * - * @param request - * the HTTP request. - * @return A new Application instance. - * @throws ServletException - */ - protected abstract Application getNewApplication(HttpServletRequest request) - throws ServletException; - - /** - * Starts the application if it is not already running. - * - * @param request - * @param application - * @param webApplicationContext - * @throws ServletException - * @throws MalformedURLException - */ - private void startApplication(HttpServletRequest request, - Application application, WebApplicationContext webApplicationContext) - throws ServletException, MalformedURLException { - - if (!application.isRunning()) { - // Create application - final URL applicationUrl = getApplicationUrl(request); - - // Initial locale comes from the request - Locale locale = request.getLocale(); - application.setLocale(locale); - application.start(new ApplicationStartEvent(applicationUrl, - getDeploymentConfiguration(), webApplicationContext)); - } - } - - /** - * Check if this is a request for a static resource and, if it is, serve the - * resource to the client. - * - * @param request - * @param response - * @return true if a file was served and the request has been handled, false - * otherwise. - * @throws IOException - * @throws ServletException - */ - private boolean serveStaticResources(HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException { - - // FIXME What does 10 refer to? - String pathInfo = request.getPathInfo(); - if (pathInfo == null || pathInfo.length() <= 10) { - return false; - } - - if ((request.getContextPath() != null) - && (request.getRequestURI().startsWith("/VAADIN/"))) { - serveStaticResourcesInVAADIN(request.getRequestURI(), request, - response); - return true; - } else if (request.getRequestURI().startsWith( - request.getContextPath() + "/VAADIN/")) { - serveStaticResourcesInVAADIN( - request.getRequestURI().substring( - request.getContextPath().length()), request, - response); - return true; - } - - return false; - } - - /** - * Serve resources from VAADIN directory. - * - * @param filename - * The filename to serve. Should always start with /VAADIN/. - * @param request - * @param response - * @throws IOException - * @throws ServletException - */ - private void serveStaticResourcesInVAADIN(String filename, - HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException { - - final ServletContext sc = getServletContext(); - URL resourceUrl = sc.getResource(filename); - if (resourceUrl == null) { - // try if requested file is found from classloader - - // strip leading "/" otherwise stream from JAR wont work - filename = filename.substring(1); - resourceUrl = getDeploymentConfiguration().getClassLoader() - .getResource(filename); - - if (resourceUrl == null) { - // cannot serve requested file - getLogger() - .info("Requested resource [" - + filename - + "] not found from filesystem or through class loader." - + " Add widgetset and/or theme JAR to your classpath or add files to WebContent/VAADIN folder."); - response.setStatus(HttpServletResponse.SC_NOT_FOUND); - return; - } - - // security check: do not permit navigation out of the VAADIN - // directory - if (!isAllowedVAADINResourceUrl(request, resourceUrl)) { - getLogger() - .info("Requested resource [" - + filename - + "] not accessible in the VAADIN directory or access to it is forbidden."); - response.setStatus(HttpServletResponse.SC_FORBIDDEN); - return; - } - } - - // Find the modification timestamp - long lastModifiedTime = 0; - URLConnection connection = null; - try { - connection = resourceUrl.openConnection(); - lastModifiedTime = connection.getLastModified(); - // Remove milliseconds to avoid comparison problems (milliseconds - // are not returned by the browser in the "If-Modified-Since" - // header). - lastModifiedTime = lastModifiedTime - lastModifiedTime % 1000; - - if (browserHasNewestVersion(request, lastModifiedTime)) { - response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); - return; - } - } catch (Exception e) { - // Failed to find out last modified timestamp. Continue without it. - getLogger() - .log(Level.FINEST, - "Failed to find out last modified timestamp. Continuing without it.", - e); - } finally { - if (connection instanceof URLConnection) { - try { - // Explicitly close the input stream to prevent it - // from remaining hanging - // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4257700 - InputStream is = connection.getInputStream(); - if (is != null) { - is.close(); - } - } catch (IOException e) { - getLogger().log(Level.INFO, - "Error closing URLConnection input stream", e); - } - } - } - - // Set type mime type if we can determine it based on the filename - final String mimetype = sc.getMimeType(filename); - if (mimetype != null) { - response.setContentType(mimetype); - } - - // Provide modification timestamp to the browser if it is known. - if (lastModifiedTime > 0) { - response.setDateHeader("Last-Modified", lastModifiedTime); - /* - * The browser is allowed to cache for 1 hour without checking if - * the file has changed. This forces browsers to fetch a new version - * when the Vaadin version is updated. This will cause more requests - * to the servlet than without this but for high volume sites the - * static files should never be served through the servlet. The - * cache timeout can be configured by setting the resourceCacheTime - * parameter in web.xml - */ - response.setHeader("Cache-Control", - "max-age= " + String.valueOf(getResourceCacheTime())); - } - - // Write the resource to the client. - final OutputStream os = response.getOutputStream(); - final byte buffer[] = new byte[DEFAULT_BUFFER_SIZE]; - int bytes; - InputStream is = resourceUrl.openStream(); - while ((bytes = is.read(buffer)) >= 0) { - os.write(buffer, 0, bytes); - } - is.close(); - } - - /** - * Check whether a URL obtained from a classloader refers to a valid static - * resource in the directory VAADIN. - * - * Warning: Overriding of this method is not recommended, but is possible to - * support non-default classloaders or servers that may produce URLs - * different from the normal ones. The method prototype may change in the - * future. Care should be taken not to expose class files or other resources - * outside the VAADIN directory if the method is overridden. - * - * @param request - * @param resourceUrl - * @return - * - * @since 6.6.7 - */ - protected boolean isAllowedVAADINResourceUrl(HttpServletRequest request, - URL resourceUrl) { - if ("jar".equals(resourceUrl.getProtocol())) { - // This branch is used for accessing resources directly from the - // Vaadin JAR in development environments and in similar cases. - - // Inside a JAR, a ".." would mean a real directory named ".." so - // using it in paths should just result in the file not being found. - // However, performing a check in case some servers or class loaders - // try to normalize the path by collapsing ".." before the class - // loader sees it. - - if (!resourceUrl.getPath().contains("!/VAADIN/")) { - getLogger().info( - "Blocked attempt to access a JAR entry not starting with /VAADIN/: " - + resourceUrl); - return false; - } - getLogger().fine( - "Accepted access to a JAR entry using a class loader: " - + resourceUrl); - return true; - } else { - // Some servers such as GlassFish extract files from JARs (file:) - // and e.g. JBoss 5+ use protocols vsf: and vfsfile: . - - // Check that the URL is in a VAADIN directory and does not contain - // "/../" - if (!resourceUrl.getPath().contains("/VAADIN/") - || resourceUrl.getPath().contains("/../")) { - getLogger().info( - "Blocked attempt to access file: " + resourceUrl); - return false; - } - getLogger().fine( - "Accepted access to a file using a class loader: " - + resourceUrl); - return true; - } - } - - /** - * Checks if the browser has an up to date cached version of requested - * resource. Currently the check is performed using the "If-Modified-Since" - * header. Could be expanded if needed. - * - * @param request - * The HttpServletRequest from the browser. - * @param resourceLastModifiedTimestamp - * The timestamp when the resource was last modified. 0 if the - * last modification time is unknown. - * @return true if the If-Modified-Since header tells the cached version in - * the browser is up to date, false otherwise - */ - private boolean browserHasNewestVersion(HttpServletRequest request, - long resourceLastModifiedTimestamp) { - if (resourceLastModifiedTimestamp < 1) { - // We do not know when it was modified so the browser cannot have an - // up-to-date version - return false; - } - /* - * The browser can request the resource conditionally using an - * If-Modified-Since header. Check this against the last modification - * time. - */ - try { - // If-Modified-Since represents the timestamp of the version cached - // in the browser - long headerIfModifiedSince = request - .getDateHeader("If-Modified-Since"); - - if (headerIfModifiedSince >= resourceLastModifiedTimestamp) { - // Browser has this an up-to-date version of the resource - return true; - } - } catch (Exception e) { - // Failed to parse header. Fail silently - the browser does not have - // an up-to-date version in its cache. - } - return false; - } - - protected enum RequestType { - FILE_UPLOAD, BROWSER_DETAILS, UIDL, OTHER, STATIC_FILE, APPLICATION_RESOURCE, CONNECTOR_RESOURCE; - } - - protected RequestType getRequestType(WrappedHttpServletRequest request) { - if (ServletPortletHelper.isFileUploadRequest(request)) { - return RequestType.FILE_UPLOAD; - } else if (ServletPortletHelper.isConnectorResourceRequest(request)) { - return RequestType.CONNECTOR_RESOURCE; - } else if (isBrowserDetailsRequest(request)) { - return RequestType.BROWSER_DETAILS; - } else if (ServletPortletHelper.isUIDLRequest(request)) { - return RequestType.UIDL; - } else if (isStaticResourceRequest(request)) { - return RequestType.STATIC_FILE; - } else if (ServletPortletHelper.isApplicationResourceRequest(request)) { - return RequestType.APPLICATION_RESOURCE; - } - return RequestType.OTHER; - - } - - private static boolean isBrowserDetailsRequest(HttpServletRequest request) { - return "POST".equals(request.getMethod()) - && request.getParameter("browserDetails") != null; - } - - private boolean isStaticResourceRequest(HttpServletRequest request) { - String pathInfo = request.getPathInfo(); - if (pathInfo == null || pathInfo.length() <= 10) { - return false; - } - - if ((request.getContextPath() != null) - && (request.getRequestURI().startsWith("/VAADIN/"))) { - return true; - } else if (request.getRequestURI().startsWith( - request.getContextPath() + "/VAADIN/")) { - return true; - } - - return false; - } - - private boolean isOnUnloadRequest(HttpServletRequest request) { - return request.getParameter(ApplicationConnection.PARAM_UNLOADBURST) != null; - } - - /** - * Get system messages from the current application class - * - * @return - */ - protected SystemMessages getSystemMessages() { - Class<? extends Application> appCls = null; - try { - appCls = getApplicationClass(); - } catch (ClassNotFoundException e) { - // Previous comment claimed that this should never happen - throw new SystemMessageException(e); - } - return getSystemMessages(appCls); - } - - public static SystemMessages getSystemMessages( - Class<? extends Application> appCls) { - try { - if (appCls != null) { - Method m = appCls - .getMethod("getSystemMessages", (Class[]) null); - return (Application.SystemMessages) m.invoke(null, - (Object[]) null); - } - } catch (SecurityException e) { - throw new SystemMessageException( - "Application.getSystemMessage() should be static public", e); - } catch (NoSuchMethodException e) { - // This is completely ok and should be silently ignored - } catch (IllegalArgumentException e) { - // This should never happen - throw new SystemMessageException(e); - } catch (IllegalAccessException e) { - throw new SystemMessageException( - "Application.getSystemMessage() should be static public", e); - } catch (InvocationTargetException e) { - // This should never happen - throw new SystemMessageException(e); - } - return Application.getSystemMessages(); - } - - protected abstract Class<? extends Application> getApplicationClass() - throws ClassNotFoundException; - - /** - * Return the URL from where static files, e.g. the widgetset and the theme, - * are served. In a standard configuration the VAADIN folder inside the - * returned folder is what is used for widgetsets and themes. - * - * The returned folder is usually the same as the context path and - * independent of the application. - * - * @param request - * @return The location of static resources (should contain the VAADIN - * directory). Never ends with a slash (/). - */ - protected String getStaticFilesLocation(HttpServletRequest request) { - - return getWebApplicationsStaticFileLocation(request); - } - - /** - * The default method to fetch static files location (URL). This method does - * not check for request attribute {@value #REQUEST_VAADIN_STATIC_FILE_PATH} - * - * @param request - * @return - */ - private String getWebApplicationsStaticFileLocation( - HttpServletRequest request) { - String staticFileLocation; - // if property is defined in configurations, use that - staticFileLocation = getDeploymentConfiguration() - .getApplicationOrSystemProperty(PARAMETER_VAADIN_RESOURCES, - null); - if (staticFileLocation != null) { - return staticFileLocation; - } - - // the last (but most common) option is to generate default location - // from request - - // if context is specified add it to widgetsetUrl - String ctxPath = request.getContextPath(); - - // FIXME: ctxPath.length() == 0 condition is probably unnecessary and - // might even be wrong. - - if (ctxPath.length() == 0 - && request.getAttribute("javax.servlet.include.context_path") != null) { - // include request (e.g portlet), get context path from - // attribute - ctxPath = (String) request - .getAttribute("javax.servlet.include.context_path"); - } - - // Remove heading and trailing slashes from the context path - ctxPath = removeHeadingOrTrailing(ctxPath, "/"); - - if (ctxPath.equals("")) { - return ""; - } else { - return "/" + ctxPath; - } - } - - /** - * Remove any heading or trailing "what" from the "string". - * - * @param string - * @param what - * @return - */ - private static String removeHeadingOrTrailing(String string, String what) { - while (string.startsWith(what)) { - string = string.substring(1); - } - - while (string.endsWith(what)) { - string = string.substring(0, string.length() - 1); - } - - return string; - } - - /** - * Write a redirect response to the main page of the application. - * - * @param request - * @param response - * @throws IOException - * if sending the redirect fails due to an input/output error or - * a bad application URL - */ - private void redirectToApplication(HttpServletRequest request, - HttpServletResponse response) throws IOException { - String applicationUrl = getApplicationUrl(request).toExternalForm(); - response.sendRedirect(response.encodeRedirectURL(applicationUrl)); - } - - /** - * Gets the current application URL from request. - * - * @param request - * the HTTP request. - * @throws MalformedURLException - * if the application is denied access to the persistent data - * store represented by the given URL. - */ - protected URL getApplicationUrl(HttpServletRequest request) - throws MalformedURLException { - final URL reqURL = new URL( - (request.isSecure() ? "https://" : "http://") - + request.getServerName() - + ((request.isSecure() && request.getServerPort() == 443) - || (!request.isSecure() && request - .getServerPort() == 80) ? "" : ":" - + request.getServerPort()) - + request.getRequestURI()); - String servletPath = ""; - if (request.getAttribute("javax.servlet.include.servlet_path") != null) { - // this is an include request - servletPath = request.getAttribute( - "javax.servlet.include.context_path").toString() - + request - .getAttribute("javax.servlet.include.servlet_path"); - - } else { - servletPath = request.getContextPath() + request.getServletPath(); - } - - if (servletPath.length() == 0 - || servletPath.charAt(servletPath.length() - 1) != '/') { - servletPath = servletPath + "/"; - } - URL u = new URL(reqURL, servletPath); - return u; - } - - /** - * Gets the existing application for given request. Looks for application - * instance for given request based on the requested URL. - * - * @param request - * the HTTP request. - * @param allowSessionCreation - * true if a session should be created if no session exists, - * false if no session should be created - * @return Application instance, or null if the URL does not map to valid - * application. - * @throws MalformedURLException - * if the application is denied access to the persistent data - * store represented by the given URL. - * @throws IllegalAccessException - * @throws InstantiationException - * @throws SessionExpiredException - */ - protected Application getExistingApplication(HttpServletRequest request, - boolean allowSessionCreation) throws MalformedURLException, - SessionExpiredException { - - // Ensures that the session is still valid - final HttpSession session = request.getSession(allowSessionCreation); - if (session == null) { - throw new SessionExpiredException(); - } - - WebApplicationContext context = getApplicationContext(session); - - // Gets application list for the session. - final Collection<Application> applications = context.getApplications(); - - // Search for the application (using the application URI) from the list - for (final Iterator<Application> i = applications.iterator(); i - .hasNext();) { - final Application sessionApplication = i.next(); - final String sessionApplicationPath = sessionApplication.getURL() - .getPath(); - String requestApplicationPath = getApplicationUrl(request) - .getPath(); - - if (requestApplicationPath.equals(sessionApplicationPath)) { - // Found a running application - if (sessionApplication.isRunning()) { - return sessionApplication; - } - // Application has stopped, so remove it before creating a new - // application - getApplicationContext(session).removeApplication( - sessionApplication); - break; - } - } - - // Existing application not found - return null; - } - - /** - * Ends the application. - * - * @param request - * the HTTP request. - * @param response - * the HTTP response to write to. - * @param application - * the application to end. - * @throws IOException - * if the writing failed due to input/output error. - */ - private void endApplication(HttpServletRequest request, - HttpServletResponse response, Application application) - throws IOException { - - String logoutUrl = application.getLogoutURL(); - if (logoutUrl == null) { - logoutUrl = application.getURL().toString(); - } - - final HttpSession session = request.getSession(); - if (session != null) { - getApplicationContext(session).removeApplication(application); - } - - response.sendRedirect(response.encodeRedirectURL(logoutUrl)); - } - - /** - * Returns the path info; note that this _can_ be different than - * request.getPathInfo(). Examples where this might be useful: - * <ul> - * <li>An application runner servlet that runs different Vaadin applications - * based on an identifier.</li> - * <li>Providing a REST interface in the context root, while serving a - * Vaadin UI on a sub-URI using only one servlet (e.g. REST on - * http://example.com/foo, UI on http://example.com/foo/vaadin)</li> - * - * @param request - * @return - */ - protected String getRequestPathInfo(HttpServletRequest request) { - return request.getPathInfo(); - } - - /** - * Gets relative location of a theme resource. - * - * @param theme - * the Theme name. - * @param resource - * the Theme resource. - * @return External URI specifying the resource - */ - public String getResourceLocation(String theme, ThemeResource resource) { - - if (resourcePath == null) { - return resource.getResourceId(); - } - return resourcePath + theme + "/" + resource.getResourceId(); - } - - private boolean isRepaintAll(HttpServletRequest request) { - return (request.getParameter(URL_PARAMETER_REPAINT_ALL) != null) - && (request.getParameter(URL_PARAMETER_REPAINT_ALL).equals("1")); - } - - private void closeApplication(Application application, HttpSession session) { - if (application == null) { - return; - } - - application.close(); - if (session != null) { - WebApplicationContext context = getApplicationContext(session); - context.removeApplication(application); - } - } - - /** - * - * Gets the application context from an HttpSession. If no context is - * currently stored in a session a new context is created and stored in the - * session. - * - * @param session - * the HTTP session. - * @return the application context for HttpSession. - */ - protected WebApplicationContext getApplicationContext(HttpSession session) { - /* - * TODO the ApplicationContext.getApplicationContext() should be removed - * and logic moved here. Now overriding context type is possible, but - * the whole creation logic should be here. MT 1101 - */ - return WebApplicationContext.getApplicationContext(session); - } - - public class RequestError implements Terminal.ErrorEvent, Serializable { - - private final Throwable throwable; - - public RequestError(Throwable throwable) { - this.throwable = throwable; - } - - @Override - public Throwable getThrowable() { - return throwable; - } - - } - - /** - * Override this method if you need to use a specialized communicaiton - * mananger implementation. - * - * @deprecated Instead of overriding this method, override - * {@link WebApplicationContext} implementation via - * {@link AbstractApplicationServlet#getApplicationContext(HttpSession)} - * method and in that customized implementation return your - * CommunicationManager in - * {@link WebApplicationContext#getApplicationManager(Application, AbstractApplicationServlet)} - * method. - * - * @param application - * @return - */ - @Deprecated - public CommunicationManager createCommunicationManager( - Application application) { - return new CommunicationManager(application); - } - - /** - * Escapes characters to html entities. An exception is made for some - * "safe characters" to keep the text somewhat readable. - * - * @param unsafe - * @return a safe string to be added inside an html tag - */ - public static final String safeEscapeForHtml(String unsafe) { - if (null == unsafe) { - return null; - } - StringBuilder safe = new StringBuilder(); - char[] charArray = unsafe.toCharArray(); - for (int i = 0; i < charArray.length; i++) { - char c = charArray[i]; - if (isSafe(c)) { - safe.append(c); - } else { - safe.append("&#"); - safe.append((int) c); - safe.append(";"); - } - } - - return safe.toString(); - } - - private static boolean isSafe(char c) { - return // - c > 47 && c < 58 || // alphanum - c > 64 && c < 91 || // A-Z - c > 96 && c < 123 // a-z - ; - } - - private static final Logger getLogger() { - return Logger.getLogger(AbstractApplicationServlet.class.getName()); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java deleted file mode 100644 index b87aaa278b..0000000000 --- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java +++ /dev/null @@ -1,2791 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.BufferedWriter; -import java.io.ByteArrayOutputStream; -import java.io.CharArrayWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.Serializable; -import java.io.StringWriter; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.net.URI; -import java.net.URISyntaxException; -import java.security.GeneralSecurityException; -import java.text.CharacterIterator; -import java.text.DateFormat; -import java.text.DateFormatSymbols; -import java.text.SimpleDateFormat; -import java.text.StringCharacterIterator; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.servlet.http.HttpServletResponse; - -import com.vaadin.Application; -import com.vaadin.Application.SystemMessages; -import com.vaadin.RootRequiresMoreInformationException; -import com.vaadin.Version; -import com.vaadin.annotations.JavaScript; -import com.vaadin.annotations.StyleSheet; -import com.vaadin.external.json.JSONArray; -import com.vaadin.external.json.JSONException; -import com.vaadin.external.json.JSONObject; -import com.vaadin.shared.Connector; -import com.vaadin.shared.communication.MethodInvocation; -import com.vaadin.shared.communication.SharedState; -import com.vaadin.shared.communication.UidlValue; -import com.vaadin.terminal.AbstractClientConnector; -import com.vaadin.terminal.CombinedRequest; -import com.vaadin.terminal.LegacyPaint; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.RequestHandler; -import com.vaadin.terminal.StreamVariable; -import com.vaadin.terminal.StreamVariable.StreamingEndEvent; -import com.vaadin.terminal.StreamVariable.StreamingErrorEvent; -import com.vaadin.terminal.Terminal.ErrorEvent; -import com.vaadin.terminal.Terminal.ErrorListener; -import com.vaadin.terminal.Vaadin6Component; -import com.vaadin.terminal.VariableOwner; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.WrappedResponse; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.server.BootstrapHandler.BootstrapContext; -import com.vaadin.terminal.gwt.server.ComponentSizeValidator.InvalidLayout; -import com.vaadin.terminal.gwt.server.RpcManager.RpcInvocationException; -import com.vaadin.ui.AbstractComponent; -import com.vaadin.ui.AbstractField; -import com.vaadin.ui.Component; -import com.vaadin.ui.ConnectorTracker; -import com.vaadin.ui.HasComponents; -import com.vaadin.ui.Root; -import com.vaadin.ui.Window; - -/** - * This is a common base class for the server-side implementations of the - * communication system between the client code (compiled with GWT into - * JavaScript) and the server side components. Its client side counterpart is - * {@link ApplicationConnection}. - * - * TODO Document better! - */ -@SuppressWarnings("serial") -public abstract class AbstractCommunicationManager implements Serializable { - - private static final String DASHDASH = "--"; - - private static final RequestHandler APP_RESOURCE_HANDLER = new ApplicationResourceHandler(); - - private static final RequestHandler UNSUPPORTED_BROWSER_HANDLER = new UnsupportedBrowserHandler(); - - /** - * TODO Document me! - * - * @author peholmst - */ - public interface Callback extends Serializable { - - public void criticalNotification(WrappedRequest request, - WrappedResponse response, String cap, String msg, - String details, String outOfSyncURL) throws IOException; - } - - static class UploadInterruptedException extends Exception { - public UploadInterruptedException() { - super("Upload interrupted by other thread"); - } - } - - private static String GET_PARAM_REPAINT_ALL = "repaintAll"; - - // flag used in the request to indicate that the security token should be - // written to the response - private static final String WRITE_SECURITY_TOKEN_FLAG = "writeSecurityToken"; - - /* Variable records indexes */ - public static final char VAR_BURST_SEPARATOR = '\u001d'; - - public static final char VAR_ESCAPE_CHARACTER = '\u001b'; - - private final HashMap<Integer, ClientCache> rootToClientCache = new HashMap<Integer, ClientCache>(); - - private static final int MAX_BUFFER_SIZE = 64 * 1024; - - /* Same as in apache commons file upload library that was previously used. */ - private static final int MAX_UPLOAD_BUFFER_SIZE = 4 * 1024; - - private static final String GET_PARAM_ANALYZE_LAYOUTS = "analyzeLayouts"; - - /** - * The application this communication manager is used for - */ - private final Application application; - - private List<String> locales; - - private int pendingLocalesIndex; - - private int timeoutInterval = -1; - - private DragAndDropService dragAndDropService; - - private String requestThemeName; - - private int maxInactiveInterval; - - private Connector highlightedConnector; - - private Map<String, Class<?>> connectorResourceContexts = new HashMap<String, Class<?>>(); - - private Map<String, Map<String, StreamVariable>> pidToNameToStreamVariable; - - private Map<StreamVariable, String> streamVariableToSeckey; - - /** - * TODO New constructor - document me! - * - * @param application - */ - public AbstractCommunicationManager(Application application) { - this.application = application; - application.addRequestHandler(getBootstrapHandler()); - application.addRequestHandler(APP_RESOURCE_HANDLER); - application.addRequestHandler(UNSUPPORTED_BROWSER_HANDLER); - requireLocale(application.getLocale().toString()); - } - - protected Application getApplication() { - return application; - } - - private static final int LF = "\n".getBytes()[0]; - - private static final String CRLF = "\r\n"; - - private static final String UTF8 = "UTF8"; - - private static final String GET_PARAM_HIGHLIGHT_COMPONENT = "highlightComponent"; - - private static String readLine(InputStream stream) throws IOException { - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - int readByte = stream.read(); - while (readByte != LF) { - bout.write(readByte); - readByte = stream.read(); - } - byte[] bytes = bout.toByteArray(); - return new String(bytes, 0, bytes.length - 1, UTF8); - } - - /** - * Method used to stream content from a multipart request (either from - * servlet or portlet request) to given StreamVariable - * - * - * @param request - * @param response - * @param streamVariable - * @param owner - * @param boundary - * @throws IOException - */ - protected void doHandleSimpleMultipartFileUpload(WrappedRequest request, - WrappedResponse response, StreamVariable streamVariable, - String variableName, ClientConnector owner, String boundary) - throws IOException { - // multipart parsing, supports only one file for request, but that is - // fine for our current terminal - - final InputStream inputStream = request.getInputStream(); - - int contentLength = request.getContentLength(); - - boolean atStart = false; - boolean firstFileFieldFound = false; - - String rawfilename = "unknown"; - String rawMimeType = "application/octet-stream"; - - /* - * Read the stream until the actual file starts (empty line). Read - * filename and content type from multipart headers. - */ - while (!atStart) { - String readLine = readLine(inputStream); - contentLength -= (readLine.length() + 2); - if (readLine.startsWith("Content-Disposition:") - && readLine.indexOf("filename=") > 0) { - rawfilename = readLine.replaceAll(".*filename=", ""); - String parenthesis = rawfilename.substring(0, 1); - rawfilename = rawfilename.substring(1); - rawfilename = rawfilename.substring(0, - rawfilename.indexOf(parenthesis)); - firstFileFieldFound = true; - } else if (firstFileFieldFound && readLine.equals("")) { - atStart = true; - } else if (readLine.startsWith("Content-Type")) { - rawMimeType = readLine.split(": ")[1]; - } - } - - contentLength -= (boundary.length() + CRLF.length() + 2 - * DASHDASH.length() + 2); // 2 == CRLF - - /* - * Reads bytes from the underlying stream. Compares the read bytes to - * the boundary string and returns -1 if met. - * - * The matching happens so that if the read byte equals to the first - * char of boundary string, the stream goes to "buffering mode". In - * buffering mode bytes are read until the character does not match the - * corresponding from boundary string or the full boundary string is - * found. - * - * Note, if this is someday needed elsewhere, don't shoot yourself to - * foot and split to a top level helper class. - */ - InputStream simpleMultiPartReader = new SimpleMultiPartInputStream( - inputStream, boundary); - - /* - * Should report only the filename even if the browser sends the path - */ - final String filename = removePath(rawfilename); - final String mimeType = rawMimeType; - - try { - // TODO Shouldn't this check connectorEnabled? - if (owner == null) { - throw new UploadException( - "File upload ignored because the connector for the stream variable was not found"); - } - if (owner instanceof Component) { - if (((Component) owner).isReadOnly()) { - throw new UploadException( - "Warning: file upload ignored because the componente was read-only"); - } - } - boolean forgetVariable = streamToReceiver(simpleMultiPartReader, - streamVariable, filename, mimeType, contentLength); - if (forgetVariable) { - cleanStreamVariable(owner, variableName); - } - } catch (Exception e) { - synchronized (application) { - handleChangeVariablesError(application, (Component) owner, e, - new HashMap<String, Object>()); - } - } - sendUploadResponse(request, response); - - } - - /** - * Used to stream plain file post (aka XHR2.post(File)) - * - * @param request - * @param response - * @param streamVariable - * @param owner - * @param contentLength - * @throws IOException - */ - protected void doHandleXhrFilePost(WrappedRequest request, - WrappedResponse response, StreamVariable streamVariable, - String variableName, ClientConnector owner, int contentLength) - throws IOException { - - // These are unknown in filexhr ATM, maybe add to Accept header that - // is accessible in portlets - final String filename = "unknown"; - final String mimeType = filename; - final InputStream stream = request.getInputStream(); - try { - /* - * safe cast as in GWT terminal all variable owners are expected to - * be components. - */ - Component component = (Component) owner; - if (component.isReadOnly()) { - throw new UploadException( - "Warning: file upload ignored because the component was read-only"); - } - boolean forgetVariable = streamToReceiver(stream, streamVariable, - filename, mimeType, contentLength); - if (forgetVariable) { - cleanStreamVariable(owner, variableName); - } - } catch (Exception e) { - synchronized (application) { - handleChangeVariablesError(application, (Component) owner, e, - new HashMap<String, Object>()); - } - } - sendUploadResponse(request, response); - } - - /** - * @param in - * @param streamVariable - * @param filename - * @param type - * @param contentLength - * @return true if the streamvariable has informed that the terminal can - * forget this variable - * @throws UploadException - */ - protected final boolean streamToReceiver(final InputStream in, - StreamVariable streamVariable, String filename, String type, - int contentLength) throws UploadException { - if (streamVariable == null) { - throw new IllegalStateException( - "StreamVariable for the post not found"); - } - - final Application application = getApplication(); - - OutputStream out = null; - int totalBytes = 0; - StreamingStartEventImpl startedEvent = new StreamingStartEventImpl( - filename, type, contentLength); - try { - boolean listenProgress; - synchronized (application) { - streamVariable.streamingStarted(startedEvent); - out = streamVariable.getOutputStream(); - listenProgress = streamVariable.listenProgress(); - } - - // Gets the output target stream - if (out == null) { - throw new NoOutputStreamException(); - } - - if (null == in) { - // No file, for instance non-existent filename in html upload - throw new NoInputStreamException(); - } - - final byte buffer[] = new byte[MAX_UPLOAD_BUFFER_SIZE]; - int bytesReadToBuffer = 0; - while ((bytesReadToBuffer = in.read(buffer)) > 0) { - out.write(buffer, 0, bytesReadToBuffer); - totalBytes += bytesReadToBuffer; - if (listenProgress) { - // update progress if listener set and contentLength - // received - synchronized (application) { - StreamingProgressEventImpl progressEvent = new StreamingProgressEventImpl( - filename, type, contentLength, totalBytes); - streamVariable.onProgress(progressEvent); - } - } - if (streamVariable.isInterrupted()) { - throw new UploadInterruptedException(); - } - } - - // upload successful - out.close(); - StreamingEndEvent event = new StreamingEndEventImpl(filename, type, - totalBytes); - synchronized (application) { - streamVariable.streamingFinished(event); - } - - } catch (UploadInterruptedException e) { - // Download interrupted by application code - tryToCloseStream(out); - StreamingErrorEvent event = new StreamingErrorEventImpl(filename, - type, contentLength, totalBytes, e); - synchronized (application) { - streamVariable.streamingFailed(event); - } - // Note, we are not throwing interrupted exception forward as it is - // not a terminal level error like all other exception. - } catch (final Exception e) { - tryToCloseStream(out); - synchronized (application) { - StreamingErrorEvent event = new StreamingErrorEventImpl( - filename, type, contentLength, totalBytes, e); - synchronized (application) { - streamVariable.streamingFailed(event); - } - // throw exception for terminal to be handled (to be passed to - // terminalErrorHandler) - throw new UploadException(e); - } - } - return startedEvent.isDisposed(); - } - - static void tryToCloseStream(OutputStream out) { - try { - // try to close output stream (e.g. file handle) - if (out != null) { - out.close(); - } - } catch (IOException e1) { - // NOP - } - } - - /** - * Removes any possible path information from the filename and returns the - * filename. Separators / and \\ are used. - * - * @param name - * @return - */ - private static String removePath(String filename) { - if (filename != null) { - filename = filename.replaceAll("^.*[/\\\\]", ""); - } - - return filename; - } - - /** - * TODO document - * - * @param request - * @param response - * @throws IOException - */ - protected void sendUploadResponse(WrappedRequest request, - WrappedResponse response) throws IOException { - response.setContentType("text/html"); - final OutputStream out = response.getOutputStream(); - final PrintWriter outWriter = new PrintWriter(new BufferedWriter( - new OutputStreamWriter(out, "UTF-8"))); - outWriter.print("<html><body>download handled</body></html>"); - outWriter.flush(); - out.close(); - } - - /** - * Internally process a UIDL request from the client. - * - * This method calls - * {@link #handleVariables(WrappedRequest, WrappedResponse, Callback, Application, Root)} - * to process any changes to variables by the client and then repaints - * affected components using {@link #paintAfterVariableChanges()}. - * - * Also, some cleanup is done when a request arrives for an application that - * has already been closed. - * - * The method handleUidlRequest(...) in subclasses should call this method. - * - * TODO better documentation - * - * @param request - * @param response - * @param callback - * @param root - * target window for the UIDL request, can be null if target not - * found - * @throws IOException - * @throws InvalidUIDLSecurityKeyException - * @throws JSONException - */ - public void handleUidlRequest(WrappedRequest request, - WrappedResponse response, Callback callback, Root root) - throws IOException, InvalidUIDLSecurityKeyException, JSONException { - - checkWidgetsetVersion(request); - requestThemeName = request.getParameter("theme"); - maxInactiveInterval = request.getSessionMaxInactiveInterval(); - // repaint requested or session has timed out and new one is created - boolean repaintAll; - final OutputStream out; - - repaintAll = (request.getParameter(GET_PARAM_REPAINT_ALL) != null); - // || (request.getSession().isNew()); FIXME What the h*ll is this?? - out = response.getOutputStream(); - - boolean analyzeLayouts = false; - if (repaintAll) { - // analyzing can be done only with repaintAll - analyzeLayouts = (request.getParameter(GET_PARAM_ANALYZE_LAYOUTS) != null); - - if (request.getParameter(GET_PARAM_HIGHLIGHT_COMPONENT) != null) { - String pid = request - .getParameter(GET_PARAM_HIGHLIGHT_COMPONENT); - highlightedConnector = root.getConnectorTracker().getConnector( - pid); - highlightConnector(highlightedConnector); - } - } - - final PrintWriter outWriter = new PrintWriter(new BufferedWriter( - new OutputStreamWriter(out, "UTF-8"))); - - // The rest of the process is synchronized with the application - // in order to guarantee that no parallel variable handling is - // made - synchronized (application) { - - // Finds the window within the application - if (application.isRunning()) { - // Returns if no window found - if (root == null) { - // This should not happen, no windows exists but - // application is still open. - getLogger().warning("Could not get root for application"); - return; - } - } else { - // application has been closed - endApplication(request, response, application); - return; - } - - // Change all variables based on request parameters - if (!handleVariables(request, response, callback, application, root)) { - - // var inconsistency; the client is probably out-of-sync - SystemMessages ci = null; - try { - Method m = application.getClass().getMethod( - "getSystemMessages", (Class[]) null); - ci = (Application.SystemMessages) m.invoke(null, - (Object[]) null); - } catch (Exception e2) { - // FIXME: Handle exception - // Not critical, but something is still wrong; print - // stacktrace - getLogger().log(Level.WARNING, - "getSystemMessages() failed - continuing", e2); - } - if (ci != null) { - String msg = ci.getOutOfSyncMessage(); - String cap = ci.getOutOfSyncCaption(); - if (msg != null || cap != null) { - callback.criticalNotification(request, response, cap, - msg, null, ci.getOutOfSyncURL()); - // will reload page after this - return; - } - } - // No message to show, let's just repaint all. - repaintAll = true; - } - - paintAfterVariableChanges(request, response, callback, repaintAll, - outWriter, root, analyzeLayouts); - postPaint(root); - } - - outWriter.close(); - requestThemeName = null; - } - - /** - * Checks that the version reported by the client (widgetset) matches that - * of the server. - * - * @param request - */ - private void checkWidgetsetVersion(WrappedRequest request) { - String widgetsetVersion = request.getParameter("wsver"); - if (widgetsetVersion == null) { - // Only check when the widgetset version is reported. It is reported - // in the first UIDL request (not the initial request as it is a - // plain GET /) - return; - } - - if (!Version.getFullVersion().equals(widgetsetVersion)) { - getLogger().warning( - String.format(Constants.WIDGETSET_MISMATCH_INFO, - Version.getFullVersion(), widgetsetVersion)); - } - } - - /** - * Method called after the paint phase while still being synchronized on the - * application - * - * @param root - * - */ - protected void postPaint(Root root) { - // Remove connectors that have been detached from the application during - // handling of the request - root.getConnectorTracker().cleanConnectorMap(); - - if (pidToNameToStreamVariable != null) { - Iterator<String> iterator = pidToNameToStreamVariable.keySet() - .iterator(); - while (iterator.hasNext()) { - String connectorId = iterator.next(); - if (root.getConnectorTracker().getConnector(connectorId) == null) { - // Owner is no longer attached to the application - Map<String, StreamVariable> removed = pidToNameToStreamVariable - .get(connectorId); - for (String key : removed.keySet()) { - streamVariableToSeckey.remove(removed.get(key)); - } - iterator.remove(); - } - } - } - } - - protected void highlightConnector(Connector highlightedConnector) { - StringBuilder sb = new StringBuilder(); - sb.append("*** Debug details of a component: *** \n"); - sb.append("Type: "); - sb.append(highlightedConnector.getClass().getName()); - if (highlightedConnector instanceof AbstractComponent) { - AbstractComponent component = (AbstractComponent) highlightedConnector; - sb.append("\nId:"); - sb.append(highlightedConnector.getConnectorId()); - if (component.getCaption() != null) { - sb.append("\nCaption:"); - sb.append(component.getCaption()); - } - - printHighlightedComponentHierarchy(sb, component); - } - getLogger().info(sb.toString()); - } - - protected void printHighlightedComponentHierarchy(StringBuilder sb, - AbstractComponent component) { - LinkedList<Component> h = new LinkedList<Component>(); - h.add(component); - Component parent = component.getParent(); - while (parent != null) { - h.addFirst(parent); - parent = parent.getParent(); - } - - sb.append("\nComponent hierarchy:\n"); - Application application2 = component.getApplication(); - sb.append(application2.getClass().getName()); - sb.append("."); - sb.append(application2.getClass().getSimpleName()); - sb.append("("); - sb.append(application2.getClass().getSimpleName()); - sb.append(".java"); - sb.append(":1)"); - int l = 1; - for (Component component2 : h) { - sb.append("\n"); - for (int i = 0; i < l; i++) { - sb.append(" "); - } - l++; - Class<? extends Component> componentClass = component2.getClass(); - Class<?> topClass = componentClass; - while (topClass.getEnclosingClass() != null) { - topClass = topClass.getEnclosingClass(); - } - sb.append(componentClass.getName()); - sb.append("."); - sb.append(componentClass.getSimpleName()); - sb.append("("); - sb.append(topClass.getSimpleName()); - sb.append(".java:1)"); - } - } - - /** - * TODO document - * - * @param request - * @param response - * @param callback - * @param repaintAll - * @param outWriter - * @param window - * @param analyzeLayouts - * @throws PaintException - * @throws IOException - * @throws JSONException - */ - private void paintAfterVariableChanges(WrappedRequest request, - WrappedResponse response, Callback callback, boolean repaintAll, - final PrintWriter outWriter, Root root, boolean analyzeLayouts) - throws PaintException, IOException, JSONException { - - // Removes application if it has stopped during variable changes - if (!application.isRunning()) { - endApplication(request, response, application); - return; - } - - openJsonMessage(outWriter, response); - - // security key - Object writeSecurityTokenFlag = request - .getAttribute(WRITE_SECURITY_TOKEN_FLAG); - - if (writeSecurityTokenFlag != null) { - outWriter.print(getSecurityKeyUIDL(request)); - } - - writeUidlResponse(request, repaintAll, outWriter, root, analyzeLayouts); - - closeJsonMessage(outWriter); - - outWriter.close(); - - } - - /** - * Gets the security key (and generates one if needed) as UIDL. - * - * @param request - * @return the security key UIDL or "" if the feature is turned off - */ - public String getSecurityKeyUIDL(WrappedRequest request) { - final String seckey = getSecurityKey(request); - if (seckey != null) { - return "\"" + ApplicationConnection.UIDL_SECURITY_TOKEN_ID - + "\":\"" + seckey + "\","; - } else { - return ""; - } - } - - /** - * Gets the security key (and generates one if needed). - * - * @param request - * @return the security key - */ - protected String getSecurityKey(WrappedRequest request) { - String seckey = null; - seckey = (String) request - .getSessionAttribute(ApplicationConnection.UIDL_SECURITY_TOKEN_ID); - if (seckey == null) { - seckey = UUID.randomUUID().toString(); - request.setSessionAttribute( - ApplicationConnection.UIDL_SECURITY_TOKEN_ID, seckey); - } - - return seckey; - } - - @SuppressWarnings("unchecked") - public void writeUidlResponse(WrappedRequest request, boolean repaintAll, - final PrintWriter outWriter, Root root, boolean analyzeLayouts) - throws PaintException, JSONException { - ArrayList<ClientConnector> dirtyVisibleConnectors = new ArrayList<ClientConnector>(); - Application application = root.getApplication(); - // Paints components - ConnectorTracker rootConnectorTracker = root.getConnectorTracker(); - getLogger().log(Level.FINE, "* Creating response to client"); - if (repaintAll) { - getClientCache(root).clear(); - rootConnectorTracker.markAllConnectorsDirty(); - - // Reset sent locales - locales = null; - requireLocale(application.getLocale().toString()); - } - - dirtyVisibleConnectors - .addAll(getDirtyVisibleConnectors(rootConnectorTracker)); - - getLogger().log( - Level.FINE, - "Found " + dirtyVisibleConnectors.size() - + " dirty connectors to paint"); - for (ClientConnector connector : dirtyVisibleConnectors) { - if (connector instanceof Component) { - ((Component) connector).updateState(); - } - } - rootConnectorTracker.markAllConnectorsClean(); - - outWriter.print("\"changes\":["); - - List<InvalidLayout> invalidComponentRelativeSizes = null; - - JsonPaintTarget paintTarget = new JsonPaintTarget(this, outWriter, - !repaintAll); - legacyPaint(paintTarget, dirtyVisibleConnectors); - - if (analyzeLayouts) { - invalidComponentRelativeSizes = ComponentSizeValidator - .validateComponentRelativeSizes(root.getContent(), null, - null); - - // Also check any existing subwindows - if (root.getWindows() != null) { - for (Window subWindow : root.getWindows()) { - invalidComponentRelativeSizes = ComponentSizeValidator - .validateComponentRelativeSizes( - subWindow.getContent(), - invalidComponentRelativeSizes, null); - } - } - } - - paintTarget.close(); - outWriter.print("], "); // close changes - - // send shared state to client - - // for now, send the complete state of all modified and new - // components - - // Ideally, all this would be sent before "changes", but that causes - // complications with legacy components that create sub-components - // in their paint phase. Nevertheless, this will be processed on the - // client after component creation but before legacy UIDL - // processing. - JSONObject sharedStates = new JSONObject(); - for (ClientConnector connector : dirtyVisibleConnectors) { - SharedState state = connector.getState(); - if (null != state) { - // encode and send shared state - try { - Class<? extends SharedState> stateType = connector - .getStateType(); - SharedState referenceState = null; - if (repaintAll) { - // Use an empty state object as reference for full - // repaints - try { - referenceState = stateType.newInstance(); - } catch (Exception e) { - getLogger().log( - Level.WARNING, - "Error creating reference object for state of type " - + stateType.getName()); - } - } - Object stateJson = JsonCodec.encode(state, referenceState, - stateType, root.getConnectorTracker()); - - sharedStates.put(connector.getConnectorId(), stateJson); - } catch (JSONException e) { - throw new PaintException( - "Failed to serialize shared state for connector " - + connector.getClass().getName() + " (" - + connector.getConnectorId() + "): " - + e.getMessage(), e); - } - } - } - outWriter.print("\"state\":"); - outWriter.append(sharedStates.toString()); - outWriter.print(", "); // close states - - // TODO This should be optimized. The type only needs to be - // sent once for each connector id + on refresh. Use the same cache as - // widget mapping - - JSONObject connectorTypes = new JSONObject(); - for (ClientConnector connector : dirtyVisibleConnectors) { - String connectorType = paintTarget.getTag(connector); - try { - connectorTypes.put(connector.getConnectorId(), connectorType); - } catch (JSONException e) { - throw new PaintException( - "Failed to send connector type for connector " - + connector.getConnectorId() + ": " - + e.getMessage(), e); - } - } - outWriter.print("\"types\":"); - outWriter.append(connectorTypes.toString()); - outWriter.print(", "); // close states - - // Send update hierarchy information to the client. - - // This could be optimized aswell to send only info if hierarchy has - // actually changed. Much like with the shared state. Note though - // that an empty hierarchy is information aswell (e.g. change from 1 - // child to 0 children) - - outWriter.print("\"hierarchy\":"); - - JSONObject hierarchyInfo = new JSONObject(); - for (ClientConnector connector : dirtyVisibleConnectors) { - String connectorId = connector.getConnectorId(); - JSONArray children = new JSONArray(); - - for (ClientConnector child : AbstractClientConnector - .getAllChildrenIterable(connector)) { - if (isVisible(child)) { - children.put(child.getConnectorId()); - } - } - try { - hierarchyInfo.put(connectorId, children); - } catch (JSONException e) { - throw new PaintException( - "Failed to send hierarchy information about " - + connectorId + " to the client: " - + e.getMessage(), e); - } - } - outWriter.append(hierarchyInfo.toString()); - outWriter.print(", "); // close hierarchy - - // send server to client RPC calls for components in the root, in call - // order - - // collect RPC calls from components in the root in the order in - // which they were performed, remove the calls from components - - LinkedList<ClientConnector> rpcPendingQueue = new LinkedList<ClientConnector>( - dirtyVisibleConnectors); - List<ClientMethodInvocation> pendingInvocations = collectPendingRpcCalls(dirtyVisibleConnectors); - - JSONArray rpcCalls = new JSONArray(); - for (ClientMethodInvocation invocation : pendingInvocations) { - // add invocation to rpcCalls - try { - JSONArray invocationJson = new JSONArray(); - invocationJson.put(invocation.getConnector().getConnectorId()); - invocationJson.put(invocation.getInterfaceName()); - invocationJson.put(invocation.getMethodName()); - JSONArray paramJson = new JSONArray(); - for (int i = 0; i < invocation.getParameterTypes().length; ++i) { - Type parameterType = invocation.getParameterTypes()[i]; - Object referenceParameter = null; - // TODO Use default values for RPC parameter types - // if (!JsonCodec.isInternalType(parameterType)) { - // try { - // referenceParameter = parameterType.newInstance(); - // } catch (Exception e) { - // logger.log(Level.WARNING, - // "Error creating reference object for parameter of type " - // + parameterType.getName()); - // } - // } - paramJson.put(JsonCodec.encode( - invocation.getParameters()[i], referenceParameter, - parameterType, root.getConnectorTracker())); - } - invocationJson.put(paramJson); - rpcCalls.put(invocationJson); - } catch (JSONException e) { - throw new PaintException( - "Failed to serialize RPC method call parameters for connector " - + invocation.getConnector().getConnectorId() - + " method " + invocation.getInterfaceName() - + "." + invocation.getMethodName() + ": " - + e.getMessage(), e); - } - - } - - if (rpcCalls.length() > 0) { - outWriter.print("\"rpc\" : "); - outWriter.append(rpcCalls.toString()); - outWriter.print(", "); // close rpc - } - - outWriter.print("\"meta\" : {"); - boolean metaOpen = false; - - if (repaintAll) { - metaOpen = true; - outWriter.write("\"repaintAll\":true"); - if (analyzeLayouts) { - outWriter.write(", \"invalidLayouts\":"); - outWriter.write("["); - if (invalidComponentRelativeSizes != null) { - boolean first = true; - for (InvalidLayout invalidLayout : invalidComponentRelativeSizes) { - if (!first) { - outWriter.write(","); - } else { - first = false; - } - invalidLayout.reportErrors(outWriter, this, System.err); - } - } - outWriter.write("]"); - } - if (highlightedConnector != null) { - outWriter.write(", \"hl\":\""); - outWriter.write(highlightedConnector.getConnectorId()); - outWriter.write("\""); - highlightedConnector = null; - } - } - - SystemMessages ci = null; - try { - Method m = application.getClass().getMethod("getSystemMessages", - (Class[]) null); - ci = (Application.SystemMessages) m.invoke(null, (Object[]) null); - } catch (NoSuchMethodException e) { - getLogger().log(Level.WARNING, - "getSystemMessages() failed - continuing", e); - } catch (IllegalArgumentException e) { - getLogger().log(Level.WARNING, - "getSystemMessages() failed - continuing", e); - } catch (IllegalAccessException e) { - getLogger().log(Level.WARNING, - "getSystemMessages() failed - continuing", e); - } catch (InvocationTargetException e) { - getLogger().log(Level.WARNING, - "getSystemMessages() failed - continuing", e); - } - - // meta instruction for client to enable auto-forward to - // sessionExpiredURL after timer expires. - if (ci != null && ci.getSessionExpiredMessage() == null - && ci.getSessionExpiredCaption() == null - && ci.isSessionExpiredNotificationEnabled()) { - int newTimeoutInterval = getTimeoutInterval(); - if (repaintAll || (timeoutInterval != newTimeoutInterval)) { - String escapedURL = ci.getSessionExpiredURL() == null ? "" : ci - .getSessionExpiredURL().replace("/", "\\/"); - if (metaOpen) { - outWriter.write(","); - } - outWriter.write("\"timedRedirect\":{\"interval\":" - + (newTimeoutInterval + 15) + ",\"url\":\"" - + escapedURL + "\"}"); - metaOpen = true; - } - timeoutInterval = newTimeoutInterval; - } - - outWriter.print("}, \"resources\" : {"); - - // Precache custom layouts - - // TODO We should only precache the layouts that are not - // cached already (plagiate from usedPaintableTypes) - int resourceIndex = 0; - for (final Iterator<Object> i = paintTarget.getUsedResources() - .iterator(); i.hasNext();) { - final String resource = (String) i.next(); - InputStream is = null; - try { - is = getThemeResourceAsStream(root, getTheme(root), resource); - } catch (final Exception e) { - // FIXME: Handle exception - getLogger().log(Level.FINER, - "Failed to get theme resource stream.", e); - } - if (is != null) { - - outWriter.print((resourceIndex++ > 0 ? ", " : "") + "\"" - + resource + "\" : "); - final StringBuffer layout = new StringBuffer(); - - try { - final InputStreamReader r = new InputStreamReader(is, - "UTF-8"); - final char[] buffer = new char[20000]; - int charsRead = 0; - while ((charsRead = r.read(buffer)) > 0) { - layout.append(buffer, 0, charsRead); - } - r.close(); - } catch (final java.io.IOException e) { - // FIXME: Handle exception - getLogger().log(Level.INFO, "Resource transfer failed", e); - } - outWriter.print("\"" - + JsonPaintTarget.escapeJSON(layout.toString()) + "\""); - } else { - // FIXME: Handle exception - getLogger().severe("CustomLayout not found: " + resource); - } - } - outWriter.print("}"); - - Collection<Class<? extends ClientConnector>> usedClientConnectors = paintTarget - .getUsedClientConnectors(); - boolean typeMappingsOpen = false; - ClientCache clientCache = getClientCache(root); - - List<Class<? extends ClientConnector>> newConnectorTypes = new ArrayList<Class<? extends ClientConnector>>(); - - for (Class<? extends ClientConnector> class1 : usedClientConnectors) { - if (clientCache.cache(class1)) { - // client does not know the mapping key for this type, send - // mapping to client - newConnectorTypes.add(class1); - - if (!typeMappingsOpen) { - typeMappingsOpen = true; - outWriter.print(", \"typeMappings\" : { "); - } else { - outWriter.print(" , "); - } - String canonicalName = class1.getCanonicalName(); - outWriter.print("\""); - outWriter.print(canonicalName); - outWriter.print("\" : "); - outWriter.print(getTagForType(class1)); - } - } - if (typeMappingsOpen) { - outWriter.print(" }"); - } - - boolean typeInheritanceMapOpen = false; - if (typeMappingsOpen) { - // send the whole type inheritance map if any new mappings - for (Class<? extends ClientConnector> class1 : usedClientConnectors) { - if (!ClientConnector.class.isAssignableFrom(class1 - .getSuperclass())) { - continue; - } - if (!typeInheritanceMapOpen) { - typeInheritanceMapOpen = true; - outWriter.print(", \"typeInheritanceMap\" : { "); - } else { - outWriter.print(" , "); - } - outWriter.print("\""); - outWriter.print(getTagForType(class1)); - outWriter.print("\" : "); - outWriter - .print(getTagForType((Class<? extends ClientConnector>) class1 - .getSuperclass())); - } - if (typeInheritanceMapOpen) { - outWriter.print(" }"); - } - } - - /* - * Ensure super classes come before sub classes to get script dependency - * order right. Sub class @JavaScript might assume that @JavaScript - * defined by super class is already loaded. - */ - Collections.sort(newConnectorTypes, new Comparator<Class<?>>() { - @Override - public int compare(Class<?> o1, Class<?> o2) { - // TODO optimize using Class.isAssignableFrom? - return hierarchyDepth(o1) - hierarchyDepth(o2); - } - - private int hierarchyDepth(Class<?> type) { - if (type == Object.class) { - return 0; - } else { - return hierarchyDepth(type.getSuperclass()) + 1; - } - } - }); - - List<String> scriptDependencies = new ArrayList<String>(); - List<String> styleDependencies = new ArrayList<String>(); - - for (Class<? extends ClientConnector> class1 : newConnectorTypes) { - JavaScript jsAnnotation = class1.getAnnotation(JavaScript.class); - if (jsAnnotation != null) { - for (String resource : jsAnnotation.value()) { - scriptDependencies.add(registerResource(resource, class1)); - } - } - - StyleSheet styleAnnotation = class1.getAnnotation(StyleSheet.class); - if (styleAnnotation != null) { - for (String resource : styleAnnotation.value()) { - styleDependencies.add(registerResource(resource, class1)); - } - } - } - - // Include script dependencies in output if there are any - if (!scriptDependencies.isEmpty()) { - outWriter.print(", \"scriptDependencies\": " - + new JSONArray(scriptDependencies).toString()); - } - - // Include style dependencies in output if there are any - if (!styleDependencies.isEmpty()) { - outWriter.print(", \"styleDependencies\": " - + new JSONArray(styleDependencies).toString()); - } - - // add any pending locale definitions requested by the client - printLocaleDeclarations(outWriter); - - if (dragAndDropService != null) { - dragAndDropService.printJSONResponse(outWriter); - } - - writePerformanceData(outWriter); - } - - /** - * Resolves a resource URI, registering the URI with this - * {@code AbstractCommunicationManager} if needed and returns a fully - * qualified URI. - */ - private String registerResource(String resourceUri, Class<?> context) { - try { - URI uri = new URI(resourceUri); - String protocol = uri.getScheme(); - - if ("connector".equals(protocol)) { - // Strip initial slash - String resourceName = uri.getPath().substring(1); - return registerConnectorResource(resourceName, context); - } - - if (protocol != null || uri.getHost() != null) { - return resourceUri; - } - - // Bare path interpreted as connector resource - return registerConnectorResource(resourceUri, context); - } catch (URISyntaxException e) { - getLogger().log(Level.WARNING, - "Could not parse resource url " + resourceUri, e); - return resourceUri; - } - } - - private String registerConnectorResource(String name, Class<?> context) { - synchronized (connectorResourceContexts) { - // Add to map of names accepted by serveConnectorResource - if (connectorResourceContexts.containsKey(name)) { - Class<?> oldContext = connectorResourceContexts.get(name); - if (oldContext != context) { - getLogger().warning( - "Resource " + name + " defined by both " + context - + " and " + oldContext + ". Resource from " - + oldContext + " will be used."); - } - } else { - connectorResourceContexts.put(name, context); - } - } - - return ApplicationConnection.CONNECTOR_PROTOCOL_PREFIX + "/" + name; - } - - /** - * Adds the performance timing data (used by TestBench 3) to the UIDL - * response. - */ - private void writePerformanceData(final PrintWriter outWriter) { - AbstractWebApplicationContext ctx = (AbstractWebApplicationContext) application - .getContext(); - outWriter.write(String.format(", \"timings\":[%d, %d]", - ctx.getTotalSessionTime(), ctx.getLastRequestTime())); - } - - private void legacyPaint(PaintTarget paintTarget, - ArrayList<ClientConnector> dirtyVisibleConnectors) - throws PaintException { - List<Vaadin6Component> legacyComponents = new ArrayList<Vaadin6Component>(); - for (Connector connector : dirtyVisibleConnectors) { - // All Components that want to use paintContent must implement - // Vaadin6Component - if (connector instanceof Vaadin6Component) { - legacyComponents.add((Vaadin6Component) connector); - } - } - sortByHierarchy((List) legacyComponents); - for (Vaadin6Component c : legacyComponents) { - getLogger().fine( - "Painting Vaadin6Component " + c.getClass().getName() + "@" - + Integer.toHexString(c.hashCode())); - paintTarget.startTag("change"); - final String pid = c.getConnectorId(); - paintTarget.addAttribute("pid", pid); - LegacyPaint.paint(c, paintTarget); - paintTarget.endTag("change"); - } - - } - - private void sortByHierarchy(List<Component> paintables) { - // Vaadin 6 requires parents to be painted before children as component - // containers rely on that their updateFromUIDL method has been called - // before children start calling e.g. updateCaption - Collections.sort(paintables, new Comparator<Component>() { - - @Override - public int compare(Component c1, Component c2) { - int depth1 = 0; - while (c1.getParent() != null) { - depth1++; - c1 = c1.getParent(); - } - int depth2 = 0; - while (c2.getParent() != null) { - depth2++; - c2 = c2.getParent(); - } - if (depth1 < depth2) { - return -1; - } - if (depth1 > depth2) { - return 1; - } - return 0; - } - }); - - } - - private ClientCache getClientCache(Root root) { - Integer rootId = Integer.valueOf(root.getRootId()); - ClientCache cache = rootToClientCache.get(rootId); - if (cache == null) { - cache = new ClientCache(); - rootToClientCache.put(rootId, cache); - } - return cache; - } - - /** - * Checks if the connector is visible in context. For Components, - * {@link #isVisible(Component)} is used. For other types of connectors, the - * contextual visibility of its first Component ancestor is used. If no - * Component ancestor is found, the connector is not visible. - * - * @param connector - * The connector to check - * @return <code>true</code> if the connector is visible to the client, - * <code>false</code> otherwise - */ - static boolean isVisible(ClientConnector connector) { - if (connector instanceof Component) { - return isVisible((Component) connector); - } else { - ClientConnector parent = connector.getParent(); - if (parent == null) { - return false; - } else { - return isVisible(parent); - } - } - } - - /** - * Checks if the component is visible in context, i.e. returns false if the - * child is hidden, the parent is hidden or the parent says the child should - * not be rendered (using - * {@link HasComponents#isComponentVisible(Component)} - * - * @param child - * The child to check - * @return true if the child is visible to the client, false otherwise - */ - static boolean isVisible(Component child) { - if (!child.isVisible()) { - return false; - } - - HasComponents parent = child.getParent(); - if (parent == null) { - if (child instanceof Root) { - return child.isVisible(); - } else { - return false; - } - } - - return parent.isComponentVisible(child) && isVisible(parent); - } - - private static class NullIterator<E> implements Iterator<E> { - - @Override - public boolean hasNext() { - return false; - } - - @Override - public E next() { - return null; - } - - @Override - public void remove() { - } - - } - - /** - * Collects all pending RPC calls from listed {@link ClientConnector}s and - * clears their RPC queues. - * - * @param rpcPendingQueue - * list of {@link ClientConnector} of interest - * @return ordered list of pending RPC calls - */ - private List<ClientMethodInvocation> collectPendingRpcCalls( - List<ClientConnector> rpcPendingQueue) { - List<ClientMethodInvocation> pendingInvocations = new ArrayList<ClientMethodInvocation>(); - for (ClientConnector connector : rpcPendingQueue) { - List<ClientMethodInvocation> paintablePendingRpc = connector - .retrievePendingRpcCalls(); - if (null != paintablePendingRpc && !paintablePendingRpc.isEmpty()) { - List<ClientMethodInvocation> oldPendingRpc = pendingInvocations; - int totalCalls = pendingInvocations.size() - + paintablePendingRpc.size(); - pendingInvocations = new ArrayList<ClientMethodInvocation>( - totalCalls); - - // merge two ordered comparable lists - for (int destIndex = 0, oldIndex = 0, paintableIndex = 0; destIndex < totalCalls; destIndex++) { - if (paintableIndex >= paintablePendingRpc.size() - || (oldIndex < oldPendingRpc.size() && ((Comparable<ClientMethodInvocation>) oldPendingRpc - .get(oldIndex)) - .compareTo(paintablePendingRpc - .get(paintableIndex)) <= 0)) { - pendingInvocations.add(oldPendingRpc.get(oldIndex++)); - } else { - pendingInvocations.add(paintablePendingRpc - .get(paintableIndex++)); - } - } - } - } - return pendingInvocations; - } - - protected abstract InputStream getThemeResourceAsStream(Root root, - String themeName, String resource); - - private int getTimeoutInterval() { - return maxInactiveInterval; - } - - private String getTheme(Root root) { - String themeName = root.getApplication().getThemeForRoot(root); - String requestThemeName = getRequestTheme(); - - if (requestThemeName != null) { - themeName = requestThemeName; - } - if (themeName == null) { - themeName = AbstractApplicationServlet.getDefaultTheme(); - } - return themeName; - } - - private String getRequestTheme() { - return requestThemeName; - } - - /** - * Returns false if the cross site request forgery protection is turned off. - * - * @param application - * @return false if the XSRF is turned off, true otherwise - */ - public boolean isXSRFEnabled(Application application) { - return !"true" - .equals(application - .getProperty(AbstractApplicationServlet.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION)); - } - - /** - * TODO document - * - * If this method returns false, something was submitted that we did not - * expect; this is probably due to the client being out-of-sync and sending - * variable changes for non-existing pids - * - * @return true if successful, false if there was an inconsistency - */ - private boolean handleVariables(WrappedRequest request, - WrappedResponse response, Callback callback, - Application application2, Root root) throws IOException, - InvalidUIDLSecurityKeyException, JSONException { - boolean success = true; - - String changes = getRequestPayload(request); - if (changes != null) { - - // Manage bursts one by one - final String[] bursts = changes.split(String - .valueOf(VAR_BURST_SEPARATOR)); - - // Security: double cookie submission pattern unless disabled by - // property - if (isXSRFEnabled(application2)) { - if (bursts.length == 1 && "init".equals(bursts[0])) { - // init request; don't handle any variables, key sent in - // response. - request.setAttribute(WRITE_SECURITY_TOKEN_FLAG, true); - return true; - } else { - // ApplicationServlet has stored the security token in the - // session; check that it matched the one sent in the UIDL - String sessId = (String) request - .getSessionAttribute(ApplicationConnection.UIDL_SECURITY_TOKEN_ID); - - if (sessId == null || !sessId.equals(bursts[0])) { - throw new InvalidUIDLSecurityKeyException( - "Security key mismatch"); - } - } - - } - - for (int bi = 1; bi < bursts.length; bi++) { - // unescape any encoded separator characters in the burst - final String burst = unescapeBurst(bursts[bi]); - success &= handleBurst(request, root, burst); - - // In case that there were multiple bursts, we know that this is - // a special synchronous case for closing window. Thus we are - // not interested in sending any UIDL changes back to client. - // Still we must clear component tree between bursts to ensure - // that no removed components are updated. The painting after - // the last burst is handled normally by the calling method. - if (bi < bursts.length - 1) { - - // We will be discarding all changes - final PrintWriter outWriter = new PrintWriter( - new CharArrayWriter()); - - paintAfterVariableChanges(request, response, callback, - true, outWriter, root, false); - - } - - } - } - /* - * Note that we ignore inconsistencies while handling unload request. - * The client can't remove invalid variable changes from the burst, and - * we don't have the required logic implemented on the server side. E.g. - * a component is removed in a previous burst. - */ - return success; - } - - /** - * Processes a message burst received from the client. - * - * A burst can contain any number of RPC calls, including legacy variable - * change calls that are processed separately. - * - * Consecutive changes to the value of the same variable are combined and - * changeVariables() is only called once for them. This preserves the Vaadin - * 6 semantics for components and add-ons that do not use Vaadin 7 RPC - * directly. - * - * @param source - * @param root - * the root receiving the burst - * @param burst - * the content of the burst as a String to be parsed - * @return true if the processing of the burst was successful and there were - * no messages to non-existent components - */ - public boolean handleBurst(WrappedRequest source, Root root, - final String burst) { - boolean success = true; - try { - Set<Connector> enabledConnectors = new HashSet<Connector>(); - - List<MethodInvocation> invocations = parseInvocations( - root.getConnectorTracker(), burst); - for (MethodInvocation invocation : invocations) { - final ClientConnector connector = getConnector(root, - invocation.getConnectorId()); - - if (connector != null && connector.isConnectorEnabled()) { - enabledConnectors.add(connector); - } - } - - for (int i = 0; i < invocations.size(); i++) { - MethodInvocation invocation = invocations.get(i); - - final ClientConnector connector = getConnector(root, - invocation.getConnectorId()); - - if (connector == null) { - getLogger().log( - Level.WARNING, - "RPC call to " + invocation.getInterfaceName() - + "." + invocation.getMethodName() - + " received for connector " - + invocation.getConnectorId() - + " but no such connector could be found"); - continue; - } - - if (!enabledConnectors.contains(connector)) { - - if (invocation instanceof LegacyChangeVariablesInvocation) { - LegacyChangeVariablesInvocation legacyInvocation = (LegacyChangeVariablesInvocation) invocation; - // TODO convert window close to a separate RPC call and - // handle above - not a variable change - - // Handle special case where window-close is called - // after the window has been removed from the - // application or the application has closed - Map<String, Object> changes = legacyInvocation - .getVariableChanges(); - if (changes.size() == 1 && changes.containsKey("close") - && Boolean.TRUE.equals(changes.get("close"))) { - // Silently ignore this - continue; - } - } - - // Connector is disabled, log a warning and move to the next - String msg = "Ignoring RPC call for disabled connector " - + connector.getClass().getName(); - if (connector instanceof Component) { - String caption = ((Component) connector).getCaption(); - if (caption != null) { - msg += ", caption=" + caption; - } - } - getLogger().warning(msg); - continue; - } - - if (invocation instanceof ServerRpcMethodInvocation) { - try { - ServerRpcManager.applyInvocation(connector, - (ServerRpcMethodInvocation) invocation); - } catch (RpcInvocationException e) { - Throwable realException = e.getCause(); - Component errorComponent = null; - if (connector instanceof Component) { - errorComponent = (Component) connector; - } - handleChangeVariablesError(root.getApplication(), - errorComponent, realException, null); - } - } else { - - // All code below is for legacy variable changes - LegacyChangeVariablesInvocation legacyInvocation = (LegacyChangeVariablesInvocation) invocation; - Map<String, Object> changes = legacyInvocation - .getVariableChanges(); - try { - if (connector instanceof VariableOwner) { - changeVariables(source, (VariableOwner) connector, - changes); - } else { - throw new IllegalStateException( - "Received legacy variable change for " - + connector.getClass().getName() - + " (" - + connector.getConnectorId() - + ") which is not a VariableOwner. The client-side connector sent these legacy varaibles: " - + changes.keySet()); - } - } catch (Exception e) { - Component errorComponent = null; - if (connector instanceof Component) { - errorComponent = (Component) connector; - } else if (connector instanceof DragAndDropService) { - Object dropHandlerOwner = changes.get("dhowner"); - if (dropHandlerOwner instanceof Component) { - errorComponent = (Component) dropHandlerOwner; - } - } - handleChangeVariablesError(root.getApplication(), - errorComponent, e, changes); - } - } - } - } catch (JSONException e) { - getLogger().warning( - "Unable to parse RPC call from the client: " - + e.getMessage()); - // TODO or return success = false? - throw new RuntimeException(e); - } - - return success; - } - - /** - * Parse a message burst from the client into a list of MethodInvocation - * instances. - * - * @param connectorTracker - * The ConnectorTracker used to lookup connectors - * @param burst - * message string (JSON) - * @return list of MethodInvocation to perform - * @throws JSONException - */ - private List<MethodInvocation> parseInvocations( - ConnectorTracker connectorTracker, final String burst) - throws JSONException { - JSONArray invocationsJson = new JSONArray(burst); - - ArrayList<MethodInvocation> invocations = new ArrayList<MethodInvocation>(); - - MethodInvocation previousInvocation = null; - // parse JSON to MethodInvocations - for (int i = 0; i < invocationsJson.length(); ++i) { - - JSONArray invocationJson = invocationsJson.getJSONArray(i); - - MethodInvocation invocation = parseInvocation(invocationJson, - previousInvocation, connectorTracker); - if (invocation != null) { - // Can be null iff the invocation was a legacy invocation and it - // was merged with the previous one - invocations.add(invocation); - previousInvocation = invocation; - } - } - return invocations; - } - - private MethodInvocation parseInvocation(JSONArray invocationJson, - MethodInvocation previousInvocation, - ConnectorTracker connectorTracker) throws JSONException { - String connectorId = invocationJson.getString(0); - String interfaceName = invocationJson.getString(1); - String methodName = invocationJson.getString(2); - - JSONArray parametersJson = invocationJson.getJSONArray(3); - - if (LegacyChangeVariablesInvocation.isLegacyVariableChange( - interfaceName, methodName)) { - if (!(previousInvocation instanceof LegacyChangeVariablesInvocation)) { - previousInvocation = null; - } - - return parseLegacyChangeVariablesInvocation(connectorId, - interfaceName, methodName, - (LegacyChangeVariablesInvocation) previousInvocation, - parametersJson, connectorTracker); - } else { - return parseServerRpcInvocation(connectorId, interfaceName, - methodName, parametersJson, connectorTracker); - } - - } - - private LegacyChangeVariablesInvocation parseLegacyChangeVariablesInvocation( - String connectorId, String interfaceName, String methodName, - LegacyChangeVariablesInvocation previousInvocation, - JSONArray parametersJson, ConnectorTracker connectorTracker) - throws JSONException { - if (parametersJson.length() != 2) { - throw new JSONException( - "Invalid parameters in legacy change variables call. Expected 2, was " - + parametersJson.length()); - } - String variableName = parametersJson.getString(0); - UidlValue uidlValue = (UidlValue) JsonCodec.decodeInternalType( - UidlValue.class, true, parametersJson.get(1), connectorTracker); - - Object value = uidlValue.getValue(); - - if (previousInvocation != null - && previousInvocation.getConnectorId().equals(connectorId)) { - previousInvocation.setVariableChange(variableName, value); - return null; - } else { - return new LegacyChangeVariablesInvocation(connectorId, - variableName, value); - } - } - - private ServerRpcMethodInvocation parseServerRpcInvocation( - String connectorId, String interfaceName, String methodName, - JSONArray parametersJson, ConnectorTracker connectorTracker) - throws JSONException { - ServerRpcMethodInvocation invocation = new ServerRpcMethodInvocation( - connectorId, interfaceName, methodName, parametersJson.length()); - - Object[] parameters = new Object[parametersJson.length()]; - Type[] declaredRpcMethodParameterTypes = invocation.getMethod() - .getGenericParameterTypes(); - - for (int j = 0; j < parametersJson.length(); ++j) { - Object parameterValue = parametersJson.get(j); - Type parameterType = declaredRpcMethodParameterTypes[j]; - parameters[j] = JsonCodec.decodeInternalOrCustomType(parameterType, - parameterValue, connectorTracker); - } - invocation.setParameters(parameters); - return invocation; - } - - protected void changeVariables(Object source, final VariableOwner owner, - Map<String, Object> m) { - owner.changeVariables(source, m); - } - - protected ClientConnector getConnector(Root root, String connectorId) { - ClientConnector c = root.getConnectorTracker() - .getConnector(connectorId); - if (c == null - && connectorId.equals(getDragAndDropService().getConnectorId())) { - return getDragAndDropService(); - } - - return c; - } - - private DragAndDropService getDragAndDropService() { - if (dragAndDropService == null) { - dragAndDropService = new DragAndDropService(this); - } - return dragAndDropService; - } - - /** - * Reads the request data from the Request and returns it converted to an - * UTF-8 string. - * - * @param request - * @return - * @throws IOException - */ - protected String getRequestPayload(WrappedRequest request) - throws IOException { - - int requestLength = request.getContentLength(); - if (requestLength == 0) { - return null; - } - - ByteArrayOutputStream bout = requestLength <= 0 ? new ByteArrayOutputStream() - : new ByteArrayOutputStream(requestLength); - - InputStream inputStream = request.getInputStream(); - byte[] buffer = new byte[MAX_BUFFER_SIZE]; - - while (true) { - int read = inputStream.read(buffer); - if (read == -1) { - break; - } - bout.write(buffer, 0, read); - } - String result = new String(bout.toByteArray(), "utf-8"); - - return result; - } - - public class ErrorHandlerErrorEvent implements ErrorEvent, Serializable { - private final Throwable throwable; - - public ErrorHandlerErrorEvent(Throwable throwable) { - this.throwable = throwable; - } - - @Override - public Throwable getThrowable() { - return throwable; - } - - } - - /** - * Handles an error (exception) that occurred when processing variable - * changes from the client or a failure of a file upload. - * - * For {@link AbstractField} components, - * {@link AbstractField#handleError(com.vaadin.ui.AbstractComponent.ComponentErrorEvent)} - * is called. In all other cases (or if the field does not handle the - * error), {@link ErrorListener#terminalError(ErrorEvent)} for the - * application error handler is called. - * - * @param application - * @param owner - * component that the error concerns - * @param e - * exception that occurred - * @param m - * map from variable names to values - */ - private void handleChangeVariablesError(Application application, - Component owner, Throwable t, Map<String, Object> m) { - boolean handled = false; - ChangeVariablesErrorEvent errorEvent = new ChangeVariablesErrorEvent( - owner, t, m); - - if (owner instanceof AbstractField) { - try { - handled = ((AbstractField<?>) owner).handleError(errorEvent); - } catch (Exception handlerException) { - /* - * If there is an error in the component error handler we pass - * the that error to the application error handler and continue - * processing the actual error - */ - application.getErrorHandler().terminalError( - new ErrorHandlerErrorEvent(handlerException)); - handled = false; - } - } - - if (!handled) { - application.getErrorHandler().terminalError(errorEvent); - } - - } - - /** - * Unescape encoded burst separator characters in a burst received from the - * client. This protects from separator injection attacks. - * - * @param encodedValue - * to decode - * @return decoded value - */ - protected String unescapeBurst(String encodedValue) { - final StringBuilder result = new StringBuilder(); - final StringCharacterIterator iterator = new StringCharacterIterator( - encodedValue); - char character = iterator.current(); - while (character != CharacterIterator.DONE) { - if (VAR_ESCAPE_CHARACTER == character) { - character = iterator.next(); - switch (character) { - case VAR_ESCAPE_CHARACTER + 0x30: - // escaped escape character - result.append(VAR_ESCAPE_CHARACTER); - break; - case VAR_BURST_SEPARATOR + 0x30: - // +0x30 makes these letters for easier reading - result.append((char) (character - 0x30)); - break; - case CharacterIterator.DONE: - // error - throw new RuntimeException( - "Communication error: Unexpected end of message"); - default: - // other escaped character - probably a client-server - // version mismatch - throw new RuntimeException( - "Invalid escaped character from the client - check that the widgetset and server versions match"); - } - } else { - // not a special character - add it to the result as is - result.append(character); - } - character = iterator.next(); - } - return result.toString(); - } - - /** - * Prints the queued (pending) locale definitions to a {@link PrintWriter} - * in a (UIDL) format that can be sent to the client and used there in - * formatting dates, times etc. - * - * @param outWriter - */ - private void printLocaleDeclarations(PrintWriter outWriter) { - /* - * ----------------------------- Sending Locale sensitive date - * ----------------------------- - */ - - // Send locale informations to client - outWriter.print(", \"locales\":["); - for (; pendingLocalesIndex < locales.size(); pendingLocalesIndex++) { - - final Locale l = generateLocale(locales.get(pendingLocalesIndex)); - // Locale name - outWriter.print("{\"name\":\"" + l.toString() + "\","); - - /* - * Month names (both short and full) - */ - final DateFormatSymbols dfs = new DateFormatSymbols(l); - final String[] short_months = dfs.getShortMonths(); - final String[] months = dfs.getMonths(); - outWriter.print("\"smn\":[\"" - + // ShortMonthNames - short_months[0] + "\",\"" + short_months[1] + "\",\"" - + short_months[2] + "\",\"" + short_months[3] + "\",\"" - + short_months[4] + "\",\"" + short_months[5] + "\",\"" - + short_months[6] + "\",\"" + short_months[7] + "\",\"" - + short_months[8] + "\",\"" + short_months[9] + "\",\"" - + short_months[10] + "\",\"" + short_months[11] + "\"" - + "],"); - outWriter.print("\"mn\":[\"" - + // MonthNames - months[0] + "\",\"" + months[1] + "\",\"" + months[2] - + "\",\"" + months[3] + "\",\"" + months[4] + "\",\"" - + months[5] + "\",\"" + months[6] + "\",\"" + months[7] - + "\",\"" + months[8] + "\",\"" + months[9] + "\",\"" - + months[10] + "\",\"" + months[11] + "\"" + "],"); - - /* - * Weekday names (both short and full) - */ - final String[] short_days = dfs.getShortWeekdays(); - final String[] days = dfs.getWeekdays(); - outWriter.print("\"sdn\":[\"" - + // ShortDayNames - short_days[1] + "\",\"" + short_days[2] + "\",\"" - + short_days[3] + "\",\"" + short_days[4] + "\",\"" - + short_days[5] + "\",\"" + short_days[6] + "\",\"" - + short_days[7] + "\"" + "],"); - outWriter.print("\"dn\":[\"" - + // DayNames - days[1] + "\",\"" + days[2] + "\",\"" + days[3] + "\",\"" - + days[4] + "\",\"" + days[5] + "\",\"" + days[6] + "\",\"" - + days[7] + "\"" + "],"); - - /* - * First day of week (0 = sunday, 1 = monday) - */ - final Calendar cal = new GregorianCalendar(l); - outWriter.print("\"fdow\":" + (cal.getFirstDayOfWeek() - 1) + ","); - - /* - * Date formatting (MM/DD/YYYY etc.) - */ - - DateFormat dateFormat = DateFormat.getDateTimeInstance( - DateFormat.SHORT, DateFormat.SHORT, l); - if (!(dateFormat instanceof SimpleDateFormat)) { - getLogger().warning( - "Unable to get default date pattern for locale " - + l.toString()); - dateFormat = new SimpleDateFormat(); - } - final String df = ((SimpleDateFormat) dateFormat).toPattern(); - - int timeStart = df.indexOf("H"); - if (timeStart < 0) { - timeStart = df.indexOf("h"); - } - final int ampm_first = df.indexOf("a"); - // E.g. in Korean locale AM/PM is before h:mm - // TODO should take that into consideration on client-side as well, - // now always h:mm a - if (ampm_first > 0 && ampm_first < timeStart) { - timeStart = ampm_first; - } - // Hebrew locale has time before the date - final boolean timeFirst = timeStart == 0; - String dateformat; - if (timeFirst) { - int dateStart = df.indexOf(' '); - if (ampm_first > dateStart) { - dateStart = df.indexOf(' ', ampm_first); - } - dateformat = df.substring(dateStart + 1); - } else { - dateformat = df.substring(0, timeStart - 1); - } - - outWriter.print("\"df\":\"" + dateformat.trim() + "\","); - - /* - * Time formatting (24 or 12 hour clock and AM/PM suffixes) - */ - final String timeformat = df.substring(timeStart, df.length()); - /* - * Doesn't return second or milliseconds. - * - * We use timeformat to determine 12/24-hour clock - */ - final boolean twelve_hour_clock = timeformat.indexOf("a") > -1; - // TODO there are other possibilities as well, like 'h' in french - // (ignore them, too complicated) - final String hour_min_delimiter = timeformat.indexOf(".") > -1 ? "." - : ":"; - // outWriter.print("\"tf\":\"" + timeformat + "\","); - outWriter.print("\"thc\":" + twelve_hour_clock + ","); - outWriter.print("\"hmd\":\"" + hour_min_delimiter + "\""); - if (twelve_hour_clock) { - final String[] ampm = dfs.getAmPmStrings(); - outWriter.print(",\"ampm\":[\"" + ampm[0] + "\",\"" + ampm[1] - + "\"]"); - } - outWriter.print("}"); - if (pendingLocalesIndex < locales.size() - 1) { - outWriter.print(","); - } - } - outWriter.print("]"); // Close locales - } - - /** - * Ends the Application. - * - * The browser is redirected to the Application logout URL set with - * {@link Application#setLogoutURL(String)}, or to the application URL if no - * logout URL is given. - * - * @param request - * the request instance. - * @param response - * the response to write to. - * @param application - * the Application to end. - * @throws IOException - * if the writing failed due to input/output error. - */ - private void endApplication(WrappedRequest request, - WrappedResponse response, Application application) - throws IOException { - - String logoutUrl = application.getLogoutURL(); - if (logoutUrl == null) { - logoutUrl = application.getURL().toString(); - } - // clients JS app is still running, send a special json file to tell - // client that application has quit and where to point browser now - // Set the response type - final OutputStream out = response.getOutputStream(); - final PrintWriter outWriter = new PrintWriter(new BufferedWriter( - new OutputStreamWriter(out, "UTF-8"))); - openJsonMessage(outWriter, response); - outWriter.print("\"redirect\":{"); - outWriter.write("\"url\":\"" + logoutUrl + "\"}"); - closeJsonMessage(outWriter); - outWriter.flush(); - outWriter.close(); - out.flush(); - } - - protected void closeJsonMessage(PrintWriter outWriter) { - outWriter.print("}]"); - } - - /** - * Writes the opening of JSON message to be sent to client. - * - * @param outWriter - * @param response - */ - protected void openJsonMessage(PrintWriter outWriter, - WrappedResponse response) { - // Sets the response type - response.setContentType("application/json; charset=UTF-8"); - // some dirt to prevent cross site scripting - outWriter.print("for(;;);[{"); - } - - /** - * Returns dirty components which are in given window. Components in an - * invisible subtrees are omitted. - * - * @param w - * root window for which dirty components is to be fetched - * @return - */ - private ArrayList<ClientConnector> getDirtyVisibleConnectors( - ConnectorTracker connectorTracker) { - ArrayList<ClientConnector> dirtyConnectors = new ArrayList<ClientConnector>(); - for (ClientConnector c : connectorTracker.getDirtyConnectors()) { - if (isVisible(c)) { - dirtyConnectors.add(c); - } - } - - return dirtyConnectors; - } - - /** - * Queues a locale to be sent to the client (browser) for date and time - * entry etc. All locale specific information is derived from server-side - * {@link Locale} instances and sent to the client when needed, eliminating - * the need to use the {@link Locale} class and all the framework behind it - * on the client. - * - * @see Locale#toString() - * - * @param value - */ - public void requireLocale(String value) { - if (locales == null) { - locales = new ArrayList<String>(); - locales.add(application.getLocale().toString()); - pendingLocalesIndex = 0; - } - if (!locales.contains(value)) { - locales.add(value); - } - } - - /** - * Constructs a {@link Locale} instance to be sent to the client based on a - * short locale description string. - * - * @see #requireLocale(String) - * - * @param value - * @return - */ - private Locale generateLocale(String value) { - final String[] temp = value.split("_"); - if (temp.length == 1) { - return new Locale(temp[0]); - } else if (temp.length == 2) { - return new Locale(temp[0], temp[1]); - } else { - return new Locale(temp[0], temp[1], temp[2]); - } - } - - protected class InvalidUIDLSecurityKeyException extends - GeneralSecurityException { - - InvalidUIDLSecurityKeyException(String message) { - super(message); - } - - } - - private final HashMap<Class<? extends ClientConnector>, Integer> typeToKey = new HashMap<Class<? extends ClientConnector>, Integer>(); - private int nextTypeKey = 0; - - private BootstrapHandler bootstrapHandler; - - String getTagForType(Class<? extends ClientConnector> class1) { - Integer id = typeToKey.get(class1); - if (id == null) { - id = nextTypeKey++; - typeToKey.put(class1, id); - getLogger().log(Level.FINE, - "Mapping " + class1.getName() + " to " + id); - } - return id.toString(); - } - - /** - * Helper class for terminal to keep track of data that client is expected - * to know. - * - * TODO make customlayout templates (from theme) to be cached here. - */ - class ClientCache implements Serializable { - - private final Set<Object> res = new HashSet<Object>(); - - /** - * - * @param paintable - * @return true if the given class was added to cache - */ - boolean cache(Object object) { - return res.add(object); - } - - public void clear() { - res.clear(); - } - - } - - public String getStreamVariableTargetUrl(ClientConnector owner, - String name, StreamVariable value) { - /* - * We will use the same APP/* URI space as ApplicationResources but - * prefix url with UPLOAD - * - * eg. APP/UPLOAD/[ROOTID]/[PID]/[NAME]/[SECKEY] - * - * SECKEY is created on each paint to make URL's unpredictable (to - * prevent CSRF attacks). - * - * NAME and PID from URI forms a key to fetch StreamVariable when - * handling post - */ - String paintableId = owner.getConnectorId(); - int rootId = owner.getRoot().getRootId(); - String key = rootId + "/" + paintableId + "/" + name; - - if (pidToNameToStreamVariable == null) { - pidToNameToStreamVariable = new HashMap<String, Map<String, StreamVariable>>(); - } - Map<String, StreamVariable> nameToStreamVariable = pidToNameToStreamVariable - .get(paintableId); - if (nameToStreamVariable == null) { - nameToStreamVariable = new HashMap<String, StreamVariable>(); - pidToNameToStreamVariable.put(paintableId, nameToStreamVariable); - } - nameToStreamVariable.put(name, value); - - if (streamVariableToSeckey == null) { - streamVariableToSeckey = new HashMap<StreamVariable, String>(); - } - String seckey = streamVariableToSeckey.get(value); - if (seckey == null) { - seckey = UUID.randomUUID().toString(); - streamVariableToSeckey.put(value, seckey); - } - - return ApplicationConnection.APP_PROTOCOL_PREFIX - + ServletPortletHelper.UPLOAD_URL_PREFIX + key + "/" + seckey; - - } - - public void cleanStreamVariable(ClientConnector owner, String name) { - Map<String, StreamVariable> nameToStreamVar = pidToNameToStreamVariable - .get(owner.getConnectorId()); - nameToStreamVar.remove(name); - if (nameToStreamVar.isEmpty()) { - pidToNameToStreamVariable.remove(owner.getConnectorId()); - } - } - - /** - * Gets the bootstrap handler that should be used for generating the pages - * bootstrapping applications for this communication manager. - * - * @return the bootstrap handler to use - */ - private BootstrapHandler getBootstrapHandler() { - if (bootstrapHandler == null) { - bootstrapHandler = createBootstrapHandler(); - } - - return bootstrapHandler; - } - - protected abstract BootstrapHandler createBootstrapHandler(); - - protected boolean handleApplicationRequest(WrappedRequest request, - WrappedResponse response) throws IOException { - return application.handleRequest(request, response); - } - - public void handleBrowserDetailsRequest(WrappedRequest request, - WrappedResponse response, Application application) - throws IOException { - - // if we do not yet have a currentRoot, it should be initialized - // shortly, and we should send the initial UIDL - boolean sendUIDL = Root.getCurrent() == null; - - try { - CombinedRequest combinedRequest = new CombinedRequest(request); - - Root root = application.getRootForRequest(combinedRequest); - response.setContentType("application/json; charset=UTF-8"); - - // Use the same logic as for determined roots - BootstrapHandler bootstrapHandler = getBootstrapHandler(); - BootstrapContext context = bootstrapHandler.createContext( - combinedRequest, response, application, root.getRootId(), - null); - - String widgetset = context.getWidgetsetName(); - String theme = context.getThemeName(); - String themeUri = bootstrapHandler.getThemeUri(context, theme); - - // TODO These are not required if it was only the init of the root - // that was delayed - JSONObject params = new JSONObject(); - params.put("widgetset", widgetset); - params.put("themeUri", themeUri); - // Root id might have changed based on e.g. window.name - params.put(ApplicationConnection.ROOT_ID_PARAMETER, - root.getRootId()); - if (sendUIDL) { - String initialUIDL = getInitialUIDL(combinedRequest, root); - params.put("uidl", initialUIDL); - } - - // NOTE! GateIn requires, for some weird reason, getOutputStream - // to be used instead of getWriter() (it seems to interpret - // application/json as a binary content type) - final OutputStream out = response.getOutputStream(); - final PrintWriter outWriter = new PrintWriter(new BufferedWriter( - new OutputStreamWriter(out, "UTF-8"))); - - outWriter.write(params.toString()); - // NOTE GateIn requires the buffers to be flushed to work - outWriter.flush(); - out.flush(); - } catch (RootRequiresMoreInformationException e) { - // Requiring more information at this point is not allowed - // TODO handle in a better way - throw new RuntimeException(e); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - /** - * Generates the initial UIDL message that can e.g. be included in a html - * page to avoid a separate round trip just for getting the UIDL. - * - * @param request - * the request that caused the initialization - * @param root - * the root for which the UIDL should be generated - * @return a string with the initial UIDL message - * @throws PaintException - * if an exception occurs while painting - * @throws JSONException - * if an exception occurs while encoding output - */ - protected String getInitialUIDL(WrappedRequest request, Root root) - throws PaintException, JSONException { - // TODO maybe unify writeUidlResponse()? - StringWriter sWriter = new StringWriter(); - PrintWriter pWriter = new PrintWriter(sWriter); - pWriter.print("{"); - if (isXSRFEnabled(root.getApplication())) { - pWriter.print(getSecurityKeyUIDL(request)); - } - writeUidlResponse(request, true, pWriter, root, false); - pWriter.print("}"); - String initialUIDL = sWriter.toString(); - getLogger().log(Level.FINE, "Initial UIDL:" + initialUIDL); - return initialUIDL; - } - - /** - * Serve a connector resource from the classpath if the resource has - * previously been registered by calling - * {@link #registerResource(String, Class)}. Sending arbitrary files from - * the classpath is prevented by only accepting resource names that have - * explicitly been registered. Resources can currently only be registered by - * including a {@link JavaScript} or {@link StyleSheet} annotation on a - * Connector class. - * - * @param request - * @param response - * - * @throws IOException - */ - public void serveConnectorResource(WrappedRequest request, - WrappedResponse response) throws IOException { - - String pathInfo = request.getRequestPathInfo(); - // + 2 to also remove beginning and ending slashes - String resourceName = pathInfo - .substring(ApplicationConnection.CONNECTOR_RESOURCE_PREFIX - .length() + 2); - - final String mimetype = response.getDeploymentConfiguration() - .getMimeType(resourceName); - - // Security check: avoid accidentally serving from the root of the - // classpath instead of relative to the context class - if (resourceName.startsWith("/")) { - getLogger().warning( - "Connector resource request starting with / rejected: " - + resourceName); - response.sendError(HttpServletResponse.SC_NOT_FOUND, resourceName); - return; - } - - // Check that the resource name has been registered - Class<?> context; - synchronized (connectorResourceContexts) { - context = connectorResourceContexts.get(resourceName); - } - - // Security check: don't serve resource if the name hasn't been - // registered in the map - if (context == null) { - getLogger().warning( - "Connector resource request for unknown resource rejected: " - + resourceName); - response.sendError(HttpServletResponse.SC_NOT_FOUND, resourceName); - return; - } - - // Resolve file relative to the location of the context class - InputStream in = context.getResourceAsStream(resourceName); - if (in == null) { - getLogger().warning( - resourceName + " defined by " + context.getName() - + " not found. Verify that the file " - + context.getPackage().getName().replace('.', '/') - + '/' + resourceName - + " is available on the classpath."); - response.sendError(HttpServletResponse.SC_NOT_FOUND, resourceName); - return; - } - - // TODO Check and set cache headers - - OutputStream out = null; - try { - if (mimetype != null) { - response.setContentType(mimetype); - } - - out = response.getOutputStream(); - - final byte[] buffer = new byte[Constants.DEFAULT_BUFFER_SIZE]; - - int bytesRead = 0; - while ((bytesRead = in.read(buffer)) > 0) { - out.write(buffer, 0, bytesRead); - } - out.flush(); - } finally { - try { - in.close(); - } catch (Exception e) { - // Do nothing - } - if (out != null) { - try { - out.close(); - } catch (Exception e) { - // Do nothing - } - } - } - } - - /** - * Handles file upload request submitted via Upload component. - * - * @param root - * The root for this request - * - * @see #getStreamVariableTargetUrl(ReceiverOwner, String, StreamVariable) - * - * @param request - * @param response - * @throws IOException - * @throws InvalidUIDLSecurityKeyException - */ - public void handleFileUpload(Application application, - WrappedRequest request, WrappedResponse response) - throws IOException, InvalidUIDLSecurityKeyException { - - /* - * URI pattern: APP/UPLOAD/[ROOTID]/[PID]/[NAME]/[SECKEY] See - * #createReceiverUrl - */ - - String pathInfo = request.getRequestPathInfo(); - // strip away part until the data we are interested starts - int startOfData = pathInfo - .indexOf(ServletPortletHelper.UPLOAD_URL_PREFIX) - + ServletPortletHelper.UPLOAD_URL_PREFIX.length(); - String uppUri = pathInfo.substring(startOfData); - String[] parts = uppUri.split("/", 4); // 0= rootid, 1 = cid, 2= name, 3 - // = sec key - String rootId = parts[0]; - String connectorId = parts[1]; - String variableName = parts[2]; - Root root = application.getRootById(Integer.parseInt(rootId)); - Root.setCurrent(root); - - StreamVariable streamVariable = getStreamVariable(connectorId, - variableName); - String secKey = streamVariableToSeckey.get(streamVariable); - if (secKey.equals(parts[3])) { - - ClientConnector source = getConnector(root, connectorId); - String contentType = request.getContentType(); - if (contentType.contains("boundary")) { - // Multipart requests contain boundary string - doHandleSimpleMultipartFileUpload(request, response, - streamVariable, variableName, source, - contentType.split("boundary=")[1]); - } else { - // if boundary string does not exist, the posted file is from - // XHR2.post(File) - doHandleXhrFilePost(request, response, streamVariable, - variableName, source, request.getContentLength()); - } - } else { - throw new InvalidUIDLSecurityKeyException( - "Security key in upload post did not match!"); - } - - } - - public StreamVariable getStreamVariable(String connectorId, - String variableName) { - Map<String, StreamVariable> map = pidToNameToStreamVariable - .get(connectorId); - if (map == null) { - return null; - } - StreamVariable streamVariable = map.get(variableName); - return streamVariable; - } - - /** - * Stream that extracts content from another stream until the boundary - * string is encountered. - * - * Public only for unit tests, should be considered private for all other - * purposes. - */ - public static class SimpleMultiPartInputStream extends InputStream { - - /** - * Counter of how many characters have been matched to boundary string - * from the stream - */ - int matchedCount = -1; - - /** - * Used as pointer when returning bytes after partly matched boundary - * string. - */ - int curBoundaryIndex = 0; - /** - * The byte found after a "promising start for boundary" - */ - private int bufferedByte = -1; - private boolean atTheEnd = false; - - private final char[] boundary; - - private final InputStream realInputStream; - - public SimpleMultiPartInputStream(InputStream realInputStream, - String boundaryString) { - boundary = (CRLF + DASHDASH + boundaryString).toCharArray(); - this.realInputStream = realInputStream; - } - - @Override - public int read() throws IOException { - if (atTheEnd) { - // End boundary reached, nothing more to read - return -1; - } else if (bufferedByte >= 0) { - /* Purge partially matched boundary if there was such */ - return getBuffered(); - } else if (matchedCount != -1) { - /* - * Special case where last "failed" matching ended with first - * character from boundary string - */ - return matchForBoundary(); - } else { - int fromActualStream = realInputStream.read(); - if (fromActualStream == -1) { - // unexpected end of stream - throw new IOException( - "The multipart stream ended unexpectedly"); - } - if (boundary[0] == fromActualStream) { - /* - * If matches the first character in boundary string, start - * checking if the boundary is fetched. - */ - return matchForBoundary(); - } - return fromActualStream; - } - } - - /** - * Reads the input to expect a boundary string. Expects that the first - * character has already been matched. - * - * @return -1 if the boundary was matched, else returns the first byte - * from boundary - * @throws IOException - */ - private int matchForBoundary() throws IOException { - matchedCount = 0; - /* - * Going to "buffered mode". Read until full boundary match or a - * different character. - */ - while (true) { - matchedCount++; - if (matchedCount == boundary.length) { - /* - * The whole boundary matched so we have reached the end of - * file - */ - atTheEnd = true; - return -1; - } - int fromActualStream = realInputStream.read(); - if (fromActualStream != boundary[matchedCount]) { - /* - * Did not find full boundary, cache the mismatching byte - * and start returning the partially matched boundary. - */ - bufferedByte = fromActualStream; - return getBuffered(); - } - } - } - - /** - * Returns the partly matched boundary string and the byte following - * that. - * - * @return - * @throws IOException - */ - private int getBuffered() throws IOException { - int b; - if (matchedCount == 0) { - // The boundary has been returned, return the buffered byte. - b = bufferedByte; - bufferedByte = -1; - matchedCount = -1; - } else { - b = boundary[curBoundaryIndex++]; - if (curBoundaryIndex == matchedCount) { - // The full boundary has been returned, remaining is the - // char that did not match the boundary. - - curBoundaryIndex = 0; - if (bufferedByte != boundary[0]) { - /* - * next call for getBuffered will return the - * bufferedByte that came after the partial boundary - * match - */ - matchedCount = 0; - } else { - /* - * Special case where buffered byte again matches the - * boundaryString. This could be the start of the real - * end boundary. - */ - matchedCount = 0; - bufferedByte = -1; - } - } - } - if (b == -1) { - throw new IOException("The multipart stream ended unexpectedly"); - } - return b; - } - } - - private static final Logger getLogger() { - return Logger.getLogger(AbstractCommunicationManager.class.getName()); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java b/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java deleted file mode 100644 index 1382c1ed53..0000000000 --- a/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java +++ /dev/null @@ -1,210 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.lang.reflect.Constructor; -import java.util.Iterator; -import java.util.Properties; -import java.util.ServiceLoader; -import java.util.logging.Logger; - -import com.vaadin.terminal.DeploymentConfiguration; - -public abstract class AbstractDeploymentConfiguration implements - DeploymentConfiguration { - - private final Class<?> systemPropertyBaseClass; - private final Properties applicationProperties = new Properties(); - private VaadinContext vaadinContext; - private boolean productionMode; - private boolean xsrfProtectionEnabled; - private int resourceCacheTime; - - public AbstractDeploymentConfiguration(Class<?> systemPropertyBaseClass) { - this.systemPropertyBaseClass = systemPropertyBaseClass; - - checkProductionMode(); - checkXsrfProtection(); - checkResourceCacheTime(); - } - - @Override - public String getApplicationOrSystemProperty(String propertyName, - String defaultValue) { - - String val = null; - - // Try application properties - val = getApplicationProperty(propertyName); - if (val != null) { - return val; - } - - // Try system properties - val = getSystemProperty(propertyName); - if (val != null) { - return val; - } - - return defaultValue; - } - - /** - * Gets an system property value. - * - * @param parameterName - * the Name or the parameter. - * @return String value or null if not found - */ - protected String getSystemProperty(String parameterName) { - String val = null; - - String pkgName; - final Package pkg = systemPropertyBaseClass.getPackage(); - if (pkg != null) { - pkgName = pkg.getName(); - } else { - final String className = systemPropertyBaseClass.getName(); - pkgName = new String(className.toCharArray(), 0, - className.lastIndexOf('.')); - } - val = System.getProperty(pkgName + "." + parameterName); - if (val != null) { - return val; - } - - // Try lowercased system properties - val = System.getProperty(pkgName + "." + parameterName.toLowerCase()); - return val; - } - - @Override - public ClassLoader getClassLoader() { - final String classLoaderName = getApplicationOrSystemProperty( - "ClassLoader", null); - ClassLoader classLoader; - if (classLoaderName == null) { - classLoader = getClass().getClassLoader(); - } else { - try { - final Class<?> classLoaderClass = getClass().getClassLoader() - .loadClass(classLoaderName); - final Constructor<?> c = classLoaderClass - .getConstructor(new Class[] { ClassLoader.class }); - classLoader = (ClassLoader) c - .newInstance(new Object[] { getClass().getClassLoader() }); - } catch (final Exception e) { - throw new RuntimeException( - "Could not find specified class loader: " - + classLoaderName, e); - } - } - return classLoader; - } - - /** - * Gets an application property value. - * - * @param parameterName - * the Name or the parameter. - * @return String value or null if not found - */ - protected String getApplicationProperty(String parameterName) { - - String val = applicationProperties.getProperty(parameterName); - if (val != null) { - return val; - } - - // Try lower case application properties for backward compatibility with - // 3.0.2 and earlier - val = applicationProperties.getProperty(parameterName.toLowerCase()); - - return val; - } - - @Override - public Properties getInitParameters() { - return applicationProperties; - } - - @Override - public Iterator<VaadinContextListener> getContextListeners() { - // Called once for init and once for destroy, so it's probably not worth - // the effort caching the ServiceLoader instance - ServiceLoader<VaadinContextListener> contextListenerLoader = ServiceLoader - .load(VaadinContextListener.class, getClassLoader()); - return contextListenerLoader.iterator(); - } - - @Override - public void setVaadinContext(VaadinContext vaadinContext) { - this.vaadinContext = vaadinContext; - } - - @Override - public VaadinContext getVaadinContext() { - return vaadinContext; - } - - @Override - public boolean isProductionMode() { - return productionMode; - } - - @Override - public boolean isXsrfProtectionEnabled() { - return xsrfProtectionEnabled; - } - - @Override - public int getResourceCacheTime() { - return resourceCacheTime; - } - - /** - * Log a warning if Vaadin is not running in production mode. - */ - private void checkProductionMode() { - productionMode = getApplicationOrSystemProperty( - Constants.SERVLET_PARAMETER_PRODUCTION_MODE, "false").equals( - "true"); - if (!productionMode) { - getLogger().warning(Constants.NOT_PRODUCTION_MODE_INFO); - } - } - - /** - * Log a warning if cross-site request forgery protection is disabled. - */ - private void checkXsrfProtection() { - xsrfProtectionEnabled = getApplicationOrSystemProperty( - Constants.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, "false") - .equals("true"); - if (!xsrfProtectionEnabled) { - getLogger().warning(Constants.WARNING_XSRF_PROTECTION_DISABLED); - } - } - - /** - * Log a warning if resource cache time is set but is not an integer. - */ - private void checkResourceCacheTime() { - try { - resourceCacheTime = Integer - .parseInt(getApplicationOrSystemProperty( - Constants.SERVLET_PARAMETER_RESOURCE_CACHE_TIME, - "3600")); - } catch (NumberFormatException e) { - getLogger().warning( - Constants.WARNING_RESOURCE_CACHING_TIME_NOT_NUMERIC); - resourceCacheTime = 3600; - } - } - - private Logger getLogger() { - return Logger.getLogger(getClass().getName()); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/AbstractStreamingEvent.java b/src/com/vaadin/terminal/gwt/server/AbstractStreamingEvent.java deleted file mode 100644 index d3474e736e..0000000000 --- a/src/com/vaadin/terminal/gwt/server/AbstractStreamingEvent.java +++ /dev/null @@ -1,46 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import com.vaadin.terminal.StreamVariable.StreamingEvent; - -/** - * Abstract base class for StreamingEvent implementations. - */ -@SuppressWarnings("serial") -abstract class AbstractStreamingEvent implements StreamingEvent { - private final String type; - private final String filename; - private final long contentLength; - private final long bytesReceived; - - @Override - public final String getFileName() { - return filename; - } - - @Override - public final String getMimeType() { - return type; - } - - protected AbstractStreamingEvent(String filename, String type, long length, - long bytesReceived) { - this.filename = filename; - this.type = type; - contentLength = length; - this.bytesReceived = bytesReceived; - } - - @Override - public final long getContentLength() { - return contentLength; - } - - @Override - public final long getBytesReceived() { - return bytesReceived; - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/AbstractWebApplicationContext.java b/src/com/vaadin/terminal/gwt/server/AbstractWebApplicationContext.java deleted file mode 100644 index 3a33621d10..0000000000 --- a/src/com/vaadin/terminal/gwt/server/AbstractWebApplicationContext.java +++ /dev/null @@ -1,268 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.PrintWriter; -import java.io.Serializable; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; -import java.net.URL; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.servlet.http.HttpSessionBindingEvent; -import javax.servlet.http.HttpSessionBindingListener; - -import com.vaadin.Application; -import com.vaadin.service.ApplicationContext; -import com.vaadin.terminal.ApplicationResource; -import com.vaadin.terminal.gwt.client.ApplicationConnection; - -/** - * Base class for web application contexts (including portlet contexts) that - * handles the common tasks. - */ -public abstract class AbstractWebApplicationContext implements - ApplicationContext, HttpSessionBindingListener, Serializable { - - protected Collection<TransactionListener> listeners = Collections - .synchronizedList(new LinkedList<TransactionListener>()); - - protected final HashSet<Application> applications = new HashSet<Application>(); - - protected WebBrowser browser = new WebBrowser(); - - protected HashMap<Application, AbstractCommunicationManager> applicationToAjaxAppMgrMap = new HashMap<Application, AbstractCommunicationManager>(); - - private long totalSessionTime = 0; - - private long lastRequestTime = -1; - - @Override - public void addTransactionListener(TransactionListener listener) { - if (listener != null) { - listeners.add(listener); - } - } - - @Override - public void removeTransactionListener(TransactionListener listener) { - listeners.remove(listener); - } - - /** - * Sends a notification that a transaction is starting. - * - * @param application - * The application associated with the transaction. - * @param request - * the HTTP or portlet request that triggered the transaction. - */ - protected void startTransaction(Application application, Object request) { - ArrayList<TransactionListener> currentListeners; - synchronized (listeners) { - currentListeners = new ArrayList<TransactionListener>(listeners); - } - for (TransactionListener listener : currentListeners) { - listener.transactionStart(application, request); - } - } - - /** - * Sends a notification that a transaction has ended. - * - * @param application - * The application associated with the transaction. - * @param request - * the HTTP or portlet request that triggered the transaction. - */ - protected void endTransaction(Application application, Object request) { - LinkedList<Exception> exceptions = null; - - ArrayList<TransactionListener> currentListeners; - synchronized (listeners) { - currentListeners = new ArrayList<TransactionListener>(listeners); - } - - for (TransactionListener listener : currentListeners) { - try { - listener.transactionEnd(application, request); - } catch (final RuntimeException t) { - if (exceptions == null) { - exceptions = new LinkedList<Exception>(); - } - exceptions.add(t); - } - } - - // If any runtime exceptions occurred, throw a combined exception - if (exceptions != null) { - final StringBuffer msg = new StringBuffer(); - for (Exception e : exceptions) { - if (msg.length() == 0) { - msg.append("\n\n--------------------------\n\n"); - } - msg.append(e.getMessage() + "\n"); - final StringWriter trace = new StringWriter(); - e.printStackTrace(new PrintWriter(trace, true)); - msg.append(trace.toString()); - } - throw new RuntimeException(msg.toString()); - } - } - - /** - * @see javax.servlet.http.HttpSessionBindingListener#valueBound(HttpSessionBindingEvent) - */ - @Override - public void valueBound(HttpSessionBindingEvent arg0) { - // We are not interested in bindings - } - - /** - * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(HttpSessionBindingEvent) - */ - @Override - public void valueUnbound(HttpSessionBindingEvent event) { - // If we are going to be unbound from the session, the session must be - // closing - try { - while (!applications.isEmpty()) { - final Application app = applications.iterator().next(); - app.close(); - removeApplication(app); - } - } catch (Exception e) { - // This should never happen but is possible with rare - // configurations (e.g. robustness tests). If you have one - // thread doing HTTP socket write and another thread trying to - // remove same application here. Possible if you got e.g. session - // lifetime 1 min but socket write may take longer than 1 min. - // FIXME: Handle exception - getLogger().log(Level.SEVERE, - "Could not remove application, leaking memory.", e); - } - } - - /** - * Get the web browser associated with this application context. - * - * Because application context is related to the http session and server - * maintains one session per browser-instance, each context has exactly one - * web browser associated with it. - * - * @return - */ - public WebBrowser getBrowser() { - return browser; - } - - @Override - public Collection<Application> getApplications() { - return Collections.unmodifiableCollection(applications); - } - - protected void removeApplication(Application application) { - applications.remove(application); - applicationToAjaxAppMgrMap.remove(application); - } - - @Override - public String generateApplicationResourceURL(ApplicationResource resource, - String mapKey) { - - final String filename = resource.getFilename(); - if (filename == null) { - return ApplicationConnection.APP_PROTOCOL_PREFIX - + ApplicationConnection.APP_REQUEST_PATH + mapKey + "/"; - } else { - // #7738 At least Tomcat and JBoss refuses requests containing - // encoded slashes or backslashes in URLs. Application resource URLs - // should really be passed in another way than as part of the path - // in the future. - String encodedFileName = urlEncode(filename).replace("%2F", "/") - .replace("%5C", "\\"); - return ApplicationConnection.APP_PROTOCOL_PREFIX - + ApplicationConnection.APP_REQUEST_PATH + mapKey + "/" - + encodedFileName; - } - - } - - static String urlEncode(String filename) { - try { - return URLEncoder.encode(filename, "UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException( - "UTF-8 charset not available (\"this should never happen\")", - e); - } - } - - @Override - public boolean isApplicationResourceURL(URL context, String relativeUri) { - // If the relative uri is null, we are ready - if (relativeUri == null) { - return false; - } - - // Resolves the prefix - String prefix = relativeUri; - final int index = relativeUri.indexOf('/'); - if (index >= 0) { - prefix = relativeUri.substring(0, index); - } - - // Handles the resource requests - return (prefix.equals("APP")); - } - - @Override - public String getURLKey(URL context, String relativeUri) { - final int index = relativeUri.indexOf('/'); - final int next = relativeUri.indexOf('/', index + 1); - if (next < 0) { - return null; - } - return relativeUri.substring(index + 1, next); - } - - /** - * @return The total time spent servicing requests in this session. - */ - public long getTotalSessionTime() { - return totalSessionTime; - } - - /** - * Sets the time spent servicing the last request in the session and updates - * the total time spent servicing requests in this session. - * - * @param time - * the time spent in the last request. - */ - public void setLastRequestTime(long time) { - lastRequestTime = time; - totalSessionTime += time; - } - - /** - * @return the time spent servicing the last request in this session. - */ - public long getLastRequestTime() { - return lastRequestTime; - } - - private Logger getLogger() { - return Logger.getLogger(AbstractWebApplicationContext.class.getName()); - } - -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationPortlet2.java b/src/com/vaadin/terminal/gwt/server/ApplicationPortlet2.java deleted file mode 100644 index 788c48267e..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ApplicationPortlet2.java +++ /dev/null @@ -1,38 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import javax.portlet.PortletConfig; -import javax.portlet.PortletException; - -import com.vaadin.Application; -import com.vaadin.terminal.gwt.server.ServletPortletHelper.ApplicationClassException; - -/** - * TODO Write documentation, fix JavaDoc tags. - * - * @author peholmst - */ -public class ApplicationPortlet2 extends AbstractApplicationPortlet { - - private Class<? extends Application> applicationClass; - - @Override - public void init(PortletConfig config) throws PortletException { - super.init(config); - try { - applicationClass = ServletPortletHelper - .getApplicationClass(getDeploymentConfiguration()); - } catch (ApplicationClassException e) { - throw new PortletException(e); - } - } - - @Override - protected Class<? extends Application> getApplicationClass() { - return applicationClass; - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationResourceHandler.java b/src/com/vaadin/terminal/gwt/server/ApplicationResourceHandler.java deleted file mode 100644 index 42726c933e..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ApplicationResourceHandler.java +++ /dev/null @@ -1,55 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.IOException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.servlet.http.HttpServletResponse; - -import com.vaadin.Application; -import com.vaadin.terminal.ApplicationResource; -import com.vaadin.terminal.DownloadStream; -import com.vaadin.terminal.RequestHandler; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.WrappedResponse; - -public class ApplicationResourceHandler implements RequestHandler { - private static final Pattern APP_RESOURCE_PATTERN = Pattern - .compile("^/?APP/(\\d+)/.*"); - - @Override - public boolean handleRequest(Application application, - WrappedRequest request, WrappedResponse response) - throws IOException { - // Check for application resources - String requestPath = request.getRequestPathInfo(); - if (requestPath == null) { - return false; - } - Matcher resourceMatcher = APP_RESOURCE_PATTERN.matcher(requestPath); - - if (resourceMatcher.matches()) { - ApplicationResource resource = application - .getResource(resourceMatcher.group(1)); - if (resource != null) { - DownloadStream stream = resource.getStream(); - if (stream != null) { - stream.setCacheTime(resource.getCacheTime()); - stream.writeTo(response); - return true; - } - } - // We get here if the url looks like an application resource but no - // resource can be served - response.sendError(HttpServletResponse.SC_NOT_FOUND, - request.getRequestPathInfo() + " can not be found"); - return true; - } - - return false; - } -} diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java deleted file mode 100644 index 1af49e0da0..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java +++ /dev/null @@ -1,78 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; - -import com.vaadin.Application; -import com.vaadin.terminal.gwt.server.ServletPortletHelper.ApplicationClassException; - -/** - * This servlet connects a Vaadin Application to Web. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.0 - */ - -@SuppressWarnings("serial") -public class ApplicationServlet extends AbstractApplicationServlet { - - // Private fields - private Class<? extends Application> applicationClass; - - /** - * Called by the servlet container to indicate to a servlet that the servlet - * is being placed into service. - * - * @param servletConfig - * the object containing the servlet's configuration and - * initialization parameters - * @throws javax.servlet.ServletException - * if an exception has occurred that interferes with the - * servlet's normal operation. - */ - @Override - public void init(javax.servlet.ServletConfig servletConfig) - throws javax.servlet.ServletException { - super.init(servletConfig); - - // Loads the application class using the classloader defined in the - // deployment configuration - - try { - applicationClass = ServletPortletHelper - .getApplicationClass(getDeploymentConfiguration()); - } catch (ApplicationClassException e) { - throw new ServletException(e); - } - } - - @Override - protected Application getNewApplication(HttpServletRequest request) - throws ServletException { - - // Creates a new application instance - try { - final Application application = getApplicationClass().newInstance(); - - return application; - } catch (final IllegalAccessException e) { - throw new ServletException("getNewApplication failed", e); - } catch (final InstantiationException e) { - throw new ServletException("getNewApplication failed", e); - } catch (ClassNotFoundException e) { - throw new ServletException("getNewApplication failed", e); - } - } - - @Override - protected Class<? extends Application> getApplicationClass() - throws ClassNotFoundException { - return applicationClass; - } -} diff --git a/src/com/vaadin/terminal/gwt/server/BootstrapDom.java b/src/com/vaadin/terminal/gwt/server/BootstrapDom.java deleted file mode 100644 index 4731a5b79f..0000000000 --- a/src/com/vaadin/terminal/gwt/server/BootstrapDom.java +++ /dev/null @@ -1,9 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -public class BootstrapDom { - -} diff --git a/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java b/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java deleted file mode 100644 index d025e93072..0000000000 --- a/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java +++ /dev/null @@ -1,643 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.Serializable; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.servlet.http.HttpServletResponse; - -import org.jsoup.nodes.DataNode; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.DocumentType; -import org.jsoup.nodes.Element; -import org.jsoup.parser.Tag; - -import com.vaadin.Application; -import com.vaadin.RootRequiresMoreInformationException; -import com.vaadin.Version; -import com.vaadin.external.json.JSONException; -import com.vaadin.external.json.JSONObject; -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.RequestHandler; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.WrappedResponse; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.ui.Root; - -public abstract class BootstrapHandler implements RequestHandler { - - protected class BootstrapContext implements Serializable { - - private final WrappedResponse response; - private final BootstrapResponse bootstrapResponse; - - private String widgetsetName; - private String themeName; - private String appId; - - public BootstrapContext(WrappedResponse response, - BootstrapResponse bootstrapResponse) { - this.response = response; - this.bootstrapResponse = bootstrapResponse; - } - - public WrappedResponse getResponse() { - return response; - } - - public WrappedRequest getRequest() { - return bootstrapResponse.getRequest(); - } - - public Application getApplication() { - return bootstrapResponse.getApplication(); - } - - public Integer getRootId() { - return bootstrapResponse.getRootId(); - } - - public Root getRoot() { - return bootstrapResponse.getRoot(); - } - - public String getWidgetsetName() { - if (widgetsetName == null) { - Root root = getRoot(); - if (root != null) { - widgetsetName = getWidgetsetForRoot(this); - } - } - return widgetsetName; - } - - public String getThemeName() { - if (themeName == null) { - Root root = getRoot(); - if (root != null) { - themeName = findAndEscapeThemeName(this); - } - } - return themeName; - } - - public String getAppId() { - if (appId == null) { - appId = getApplicationId(this); - } - return appId; - } - - public BootstrapResponse getBootstrapResponse() { - return bootstrapResponse; - } - - } - - @Override - public boolean handleRequest(Application application, - WrappedRequest request, WrappedResponse response) - throws IOException { - - // TODO Should all urls be handled here? - Integer rootId = null; - try { - Root root = application.getRootForRequest(request); - if (root == null) { - writeError(response, new Throwable("No Root found")); - return true; - } - - rootId = Integer.valueOf(root.getRootId()); - } catch (RootRequiresMoreInformationException e) { - // Just keep going without rootId - } - - try { - writeBootstrapPage(request, response, application, rootId); - } catch (JSONException e) { - writeError(response, e); - } - - return true; - } - - protected final void writeBootstrapPage(WrappedRequest request, - WrappedResponse response, Application application, Integer rootId) - throws IOException, JSONException { - - Map<String, Object> headers = new LinkedHashMap<String, Object>(); - BootstrapContext context = createContext(request, response, - application, rootId, headers); - - DeploymentConfiguration deploymentConfiguration = request - .getDeploymentConfiguration(); - - boolean standalone = deploymentConfiguration.isStandalone(request); - if (standalone) { - setBootstrapPageHeaders(context); - setBasicHtml(context); - setBootstrapPageHtmlHeader(context); - setBodyTag(context); - } - - setBootstrapPageHtmlVaadinScripts(context); - - setMainDiv(context); - - request.getDeploymentConfiguration().getVaadinContext() - .fireModifyBootstrapEvent(context.getBootstrapResponse()); - - response.setContentType("text/html"); - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter( - response.getOutputStream(), "UTF-8")); - if (standalone) { - Set<Entry<String, Object>> entrySet = headers.entrySet(); - for (Entry<String, Object> header : entrySet) { - Object value = header.getValue(); - if (value instanceof String) { - response.setHeader(header.getKey(), (String) value); - } else if (value instanceof Long) { - response.setDateHeader(header.getKey(), - ((Long) value).longValue()); - } else { - throw new RuntimeException("Unsupported header value: " - + value); - } - } - writer.append(context.getBootstrapResponse().getDocument() - .outerHtml()); - } else { - writer.append(context.getBootstrapResponse().getApplicationTag() - .outerHtml()); - } - writer.close(); - } - - public BootstrapContext createContext(WrappedRequest request, - WrappedResponse response, Application application, Integer rootId, - Map<String, Object> headers) { - boolean standalone = request.getDeploymentConfiguration().isStandalone( - request); - Document document; - Element applicationTag; - if (standalone) { - document = Document.createShell(""); - applicationTag = document.body(); - } else { - document = null; - applicationTag = new Element(Tag.valueOf("div"), ""); - } - BootstrapContext context = new BootstrapContext(response, - new BootstrapResponse(this, request, document, applicationTag, - headers, application, rootId)); - return context; - } - - protected String getMainDivStyle(BootstrapContext context) { - return null; - } - - /** - * Creates and returns a unique ID for the DIV where the application is to - * be rendered. - * - * @param context - * - * @return the id to use in the DOM - */ - protected abstract String getApplicationId(BootstrapContext context); - - public String getWidgetsetForRoot(BootstrapContext context) { - Root root = context.getRoot(); - WrappedRequest request = context.getRequest(); - - String widgetset = root.getApplication().getWidgetsetForRoot(root); - if (widgetset == null) { - widgetset = request.getDeploymentConfiguration() - .getConfiguredWidgetset(request); - } - - widgetset = AbstractApplicationServlet.stripSpecialChars(widgetset); - return widgetset; - } - - /** - * Method to write the div element into which that actual Vaadin application - * is rendered. - * <p> - * Override this method if you want to add some custom html around around - * the div element into which the actual Vaadin application will be - * rendered. - * - * @param context - * - * @throws IOException - */ - protected void setMainDiv(BootstrapContext context) throws IOException { - String style = getMainDivStyle(context); - - /*- Add classnames; - * .v-app - * .v-app-loading - * .v-app-<simpleName for app class> - *- Additionally added from javascript: - * .v-theme-<themeName, remove non-alphanum> - */ - - String appClass = "v-app-" - + getApplicationCSSClassName(context.getApplication()); - - String classNames = "v-app " + appClass; - - Element applicationTag = context.getBootstrapResponse() - .getApplicationTag(); - Element mainDiv = applicationTag.appendElement("div"); - mainDiv.attr("id", context.getAppId()); - mainDiv.addClass(classNames); - if (style != null && style.length() != 0) { - mainDiv.attr("style", style); - } - mainDiv.appendElement("div").addClass("v-app-loading"); - mainDiv.appendElement("noscript").append(getNoScriptMessage()); - } - - /** - * Returns a message printed for browsers without scripting support or if - * browsers scripting support is disabled. - */ - protected String getNoScriptMessage() { - return "You have to enable javascript in your browser to use an application built with Vaadin."; - } - - /** - * Returns the application class identifier for use in the application CSS - * class name in the root DIV. The application CSS class name is of form - * "v-app-"+getApplicationCSSClassName(). - * - * This method should normally not be overridden. - * - * @return The CSS class name to use in combination with "v-app-". - */ - protected String getApplicationCSSClassName(Application application) { - return application.getClass().getSimpleName(); - } - - /** - * - * Method to open the body tag of the html kickstart page. - * <p> - * This method is responsible for closing the head tag and opening the body - * tag. - * <p> - * Override this method if you want to add some custom html to the page. - * - * @throws IOException - */ - protected void setBodyTag(BootstrapContext context) throws IOException { - Element body = context.getBootstrapResponse().getDocument().body(); - body.attr("scroll", "auto"); - body.addClass(ApplicationConnection.GENERATED_BODY_CLASSNAME); - } - - /** - * Method to write the script part of the page which loads needed Vaadin - * scripts and themes. - * <p> - * Override this method if you want to add some custom html around scripts. - * - * @param context - * - * @throws IOException - * @throws JSONException - */ - protected void setBootstrapPageHtmlVaadinScripts(BootstrapContext context) - throws IOException, JSONException { - WrappedRequest request = context.getRequest(); - - DeploymentConfiguration deploymentConfiguration = request - .getDeploymentConfiguration(); - String staticFileLocation = deploymentConfiguration - .getStaticFileLocation(request); - - Element applicationTag = context.getBootstrapResponse() - .getApplicationTag(); - - applicationTag - .appendElement("iframe") - .attr("tabIndex", "-1") - .attr("id", "__gwt_historyFrame") - .attr("style", - "position:absolute;width:0;height:0;border:0;overflow:hidden") - .attr("src", "javascript:false"); - - String bootstrapLocation = staticFileLocation - + "/VAADIN/vaadinBootstrap.js"; - applicationTag.appendElement("script").attr("type", "text/javascript") - .attr("src", bootstrapLocation); - Element mainScriptTag = applicationTag.appendElement("script").attr( - "type", "text/javascript"); - - StringBuilder builder = new StringBuilder(); - builder.append("//<![CDATA[\n"); - builder.append("if (!window.vaadin) alert(" - + JSONObject.quote("Failed to load the bootstrap javascript: " - + bootstrapLocation) + ");\n"); - - appendMainScriptTagContents(context, builder); - - builder.append("//]]>"); - mainScriptTag.appendChild(new DataNode(builder.toString(), - mainScriptTag.baseUri())); - } - - protected void appendMainScriptTagContents(BootstrapContext context, - StringBuilder builder) throws JSONException, IOException { - JSONObject defaults = getDefaultParameters(context); - JSONObject appConfig = getApplicationParameters(context); - - boolean isDebug = !context.getApplication().isProductionMode(); - - builder.append("vaadin.setDefaults("); - appendJsonObject(builder, defaults, isDebug); - builder.append(");\n"); - - builder.append("vaadin.initApplication(\""); - builder.append(context.getAppId()); - builder.append("\","); - appendJsonObject(builder, appConfig, isDebug); - builder.append(");\n"); - } - - private static void appendJsonObject(StringBuilder builder, - JSONObject jsonObject, boolean isDebug) throws JSONException { - if (isDebug) { - builder.append(jsonObject.toString(4)); - } else { - builder.append(jsonObject.toString()); - } - } - - protected JSONObject getApplicationParameters(BootstrapContext context) - throws JSONException, PaintException { - Application application = context.getApplication(); - Integer rootId = context.getRootId(); - - JSONObject appConfig = new JSONObject(); - - if (rootId != null) { - appConfig.put(ApplicationConnection.ROOT_ID_PARAMETER, rootId); - } - - if (context.getThemeName() != null) { - appConfig.put("themeUri", - getThemeUri(context, context.getThemeName())); - } - - JSONObject versionInfo = new JSONObject(); - versionInfo.put("vaadinVersion", Version.getFullVersion()); - versionInfo.put("applicationVersion", application.getVersion()); - appConfig.put("versionInfo", versionInfo); - - appConfig.put("widgetset", context.getWidgetsetName()); - - if (rootId == null || application.isRootInitPending(rootId.intValue())) { - appConfig.put("initialPath", context.getRequest() - .getRequestPathInfo()); - - Map<String, String[]> parameterMap = context.getRequest() - .getParameterMap(); - appConfig.put("initialParams", parameterMap); - } else { - // write the initial UIDL into the config - appConfig.put("uidl", - getInitialUIDL(context.getRequest(), context.getRoot())); - } - - return appConfig; - } - - protected JSONObject getDefaultParameters(BootstrapContext context) - throws JSONException { - JSONObject defaults = new JSONObject(); - - WrappedRequest request = context.getRequest(); - Application application = context.getApplication(); - - // Get system messages - Application.SystemMessages systemMessages = AbstractApplicationServlet - .getSystemMessages(application.getClass()); - if (systemMessages != null) { - // Write the CommunicationError -message to client - JSONObject comErrMsg = new JSONObject(); - comErrMsg.put("caption", - systemMessages.getCommunicationErrorCaption()); - comErrMsg.put("message", - systemMessages.getCommunicationErrorMessage()); - comErrMsg.put("url", systemMessages.getCommunicationErrorURL()); - - defaults.put("comErrMsg", comErrMsg); - - JSONObject authErrMsg = new JSONObject(); - authErrMsg.put("caption", - systemMessages.getAuthenticationErrorCaption()); - authErrMsg.put("message", - systemMessages.getAuthenticationErrorMessage()); - authErrMsg.put("url", systemMessages.getAuthenticationErrorURL()); - - defaults.put("authErrMsg", authErrMsg); - } - - DeploymentConfiguration deploymentConfiguration = request - .getDeploymentConfiguration(); - String staticFileLocation = deploymentConfiguration - .getStaticFileLocation(request); - String widgetsetBase = staticFileLocation + "/" - + AbstractApplicationServlet.WIDGETSET_DIRECTORY_PATH; - defaults.put("widgetsetBase", widgetsetBase); - - if (!application.isProductionMode()) { - defaults.put("debug", true); - } - - if (deploymentConfiguration.isStandalone(request)) { - defaults.put("standalone", true); - } - - defaults.put("appUri", getAppUri(context)); - - return defaults; - } - - protected abstract String getAppUri(BootstrapContext context); - - /** - * Method to write the contents of head element in html kickstart page. - * <p> - * Override this method if you want to add some custom html to the header of - * the page. - * - * @throws IOException - */ - protected void setBootstrapPageHtmlHeader(BootstrapContext context) - throws IOException { - String themeName = context.getThemeName(); - Element head = context.getBootstrapResponse().getDocument().head(); - head.appendElement("meta").attr("http-equiv", "Content-Type") - .attr("content", "text/html; charset=utf-8"); - - // Chrome frame in all versions of IE (only if Chrome frame is - // installed) - head.appendElement("meta").attr("http-equiv", "X-UA-Compatible") - .attr("content", "chrome=1"); - - head.appendElement("style").attr("type", "text/css") - .appendText("html, body {height:100%;margin:0;}"); - - // Add favicon links - if (themeName != null) { - String themeUri = getThemeUri(context, themeName); - head.appendElement("link").attr("rel", "shortcut icon") - .attr("type", "image/vnd.microsoft.icon") - .attr("href", themeUri + "/favicon.ico"); - head.appendElement("link").attr("rel", "icon") - .attr("type", "image/vnd.microsoft.icon") - .attr("href", themeUri + "/favicon.ico"); - } - - Root root = context.getRoot(); - String title = ((root == null || root.getCaption() == null) ? "" : root - .getCaption()); - - head.appendElement("title").appendText(title); - } - - /** - * Method to set http request headers for the Vaadin kickstart page. - * <p> - * Override this method if you need to customize http headers of the page. - * - * @param context - */ - protected void setBootstrapPageHeaders(BootstrapContext context) { - WrappedResponse response = context.getResponse(); - - // Window renders are not cacheable - response.setHeader("Cache-Control", "no-cache"); - response.setHeader("Pragma", "no-cache"); - response.setDateHeader("Expires", 0); - response.setContentType("text/html; charset=UTF-8"); - } - - /** - * Method to write the beginning of the html page. - * <p> - * This method is responsible for writing appropriate doc type declarations - * and to open html and head tags. - * <p> - * Override this method if you want to add some custom html to the very - * beginning of the page. - * - * @param context - * @throws IOException - */ - protected void setBasicHtml(BootstrapContext context) throws IOException { - - // write html header - // page.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD " - // + "XHTML 1.0 Transitional//EN\" " - // + "\"http://www.w3.org/TR/xhtml1/" - // + "DTD/xhtml1-transitional.dtd\">\n"); - Document document = context.getBootstrapResponse().getDocument(); - DocumentType doctype = new DocumentType("html", - "//W3C//DTD XHTML 1.0 Transitional//EN", - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", - document.baseUri()); - document.child(0).before(doctype); - - document.body().parent().attr("xmlns", "http://www.w3.org/1999/xhtml"); - } - - /** - * Get the URI for the application theme. - * - * A portal-wide default theme is fetched from the portal shared resource - * directory (if any), other themes from the portlet. - * - * @param context - * @param themeName - * - * @return - */ - public String getThemeUri(BootstrapContext context, String themeName) { - WrappedRequest request = context.getRequest(); - final String staticFilePath = request.getDeploymentConfiguration() - .getStaticFileLocation(request); - return staticFilePath + "/" - + AbstractApplicationServlet.THEME_DIRECTORY_PATH + themeName; - } - - /** - * Override if required - * - * @param context - * @return - */ - public String getThemeName(BootstrapContext context) { - return context.getApplication().getThemeForRoot(context.getRoot()); - } - - /** - * Don not override. - * - * @param context - * @return - */ - public String findAndEscapeThemeName(BootstrapContext context) { - String themeName = getThemeName(context); - if (themeName == null) { - WrappedRequest request = context.getRequest(); - themeName = request.getDeploymentConfiguration() - .getConfiguredTheme(request); - } - - // XSS preventation, theme names shouldn't contain special chars anyway. - // The servlet denies them via url parameter. - themeName = AbstractApplicationServlet.stripSpecialChars(themeName); - - return themeName; - } - - protected void writeError(WrappedResponse response, Throwable e) - throws IOException { - response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - e.getLocalizedMessage()); - } - - /** - * Gets the initial UIDL message to send to the client. - * - * @param request - * the originating request - * @param root - * the root for which the UIDL should be generated - * @return a string with the initial UIDL message - * @throws PaintException - * if an exception occurs while painting the components - * @throws JSONException - * if an exception occurs while formatting the output - */ - protected abstract String getInitialUIDL(WrappedRequest request, Root root) - throws PaintException, JSONException; - -} diff --git a/src/com/vaadin/terminal/gwt/server/BootstrapListener.java b/src/com/vaadin/terminal/gwt/server/BootstrapListener.java deleted file mode 100644 index 54bd13c25a..0000000000 --- a/src/com/vaadin/terminal/gwt/server/BootstrapListener.java +++ /dev/null @@ -1,11 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.util.EventListener; - -public interface BootstrapListener extends EventListener { - public void modifyBootstrap(BootstrapResponse response); -} diff --git a/src/com/vaadin/terminal/gwt/server/BootstrapResponse.java b/src/com/vaadin/terminal/gwt/server/BootstrapResponse.java deleted file mode 100644 index 37b59989f6..0000000000 --- a/src/com/vaadin/terminal/gwt/server/BootstrapResponse.java +++ /dev/null @@ -1,72 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.util.EventObject; -import java.util.Map; - -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; - -import com.vaadin.Application; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.ui.Root; - -public class BootstrapResponse extends EventObject { - private final Document document; - private final WrappedRequest request; - private final Map<String, Object> headers; - private final Element applicationTag; - private final Application application; - private final Integer rootId; - - public BootstrapResponse(BootstrapHandler handler, WrappedRequest request, - Document document, Element applicationTag, - Map<String, Object> headers, Application application, Integer rootId) { - super(handler); - this.request = request; - this.document = document; - this.applicationTag = applicationTag; - this.headers = headers; - this.application = application; - this.rootId = rootId; - } - - public void setHeader(String name, String value) { - headers.put(name, value); - } - - public void setDateHeader(String name, long timestamp) { - headers.put(name, Long.valueOf(timestamp)); - } - - public BootstrapHandler getBootstrapHandler() { - return (BootstrapHandler) getSource(); - } - - public WrappedRequest getRequest() { - return request; - } - - public Document getDocument() { - return document; - } - - public Element getApplicationTag() { - return applicationTag; - } - - public Application getApplication() { - return application; - } - - public Integer getRootId() { - return rootId; - } - - public Root getRoot() { - return Root.getCurrent(); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/ChangeVariablesErrorEvent.java b/src/com/vaadin/terminal/gwt/server/ChangeVariablesErrorEvent.java deleted file mode 100644 index 8f0c80332f..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ChangeVariablesErrorEvent.java +++ /dev/null @@ -1,39 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.util.Map; - -import com.vaadin.ui.AbstractComponent.ComponentErrorEvent; -import com.vaadin.ui.Component; - -@SuppressWarnings("serial") -public class ChangeVariablesErrorEvent implements ComponentErrorEvent { - - private Throwable throwable; - private Component component; - - private Map<String, Object> variableChanges; - - public ChangeVariablesErrorEvent(Component component, Throwable throwable, - Map<String, Object> variableChanges) { - this.component = component; - this.throwable = throwable; - this.variableChanges = variableChanges; - } - - @Override - public Throwable getThrowable() { - return throwable; - } - - public Component getComponent() { - return component; - } - - public Map<String, Object> getVariableChanges() { - return variableChanges; - } - -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/ClientConnector.java b/src/com/vaadin/terminal/gwt/server/ClientConnector.java deleted file mode 100644 index 4f74cfe4bb..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ClientConnector.java +++ /dev/null @@ -1,149 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.util.Collection; -import java.util.List; - -import com.vaadin.shared.Connector; -import com.vaadin.shared.communication.SharedState; -import com.vaadin.terminal.AbstractClientConnector; -import com.vaadin.terminal.Extension; -import com.vaadin.ui.Component; -import com.vaadin.ui.ComponentContainer; -import com.vaadin.ui.Root; - -/** - * Interface implemented by all connectors that are capable of communicating - * with the client side - * - * @author Vaadin Ltd - * @version @VERSION@ - * @since 7.0.0 - * - */ -public interface ClientConnector extends Connector, RpcTarget { - /** - * Returns the list of pending server to client RPC calls and clears the - * list. - * - * @return an unmodifiable ordered list of pending server to client method - * calls (not null) - */ - public List<ClientMethodInvocation> retrievePendingRpcCalls(); - - /** - * Checks if the communicator is enabled. An enabled communicator is allowed - * to receive messages from its counter-part. - * - * @return true if the connector can receive messages, false otherwise - */ - public boolean isConnectorEnabled(); - - /** - * Returns the type of the shared state for this connector - * - * @return The type of the state. Must never return null. - */ - public Class<? extends SharedState> getStateType(); - - @Override - public ClientConnector getParent(); - - /** - * Requests that the connector should be repainted as soon as possible. - */ - public void requestRepaint(); - - /** - * Causes a repaint of this connector, and all connectors below it. - * - * This should only be used in special cases, e.g when the state of a - * descendant depends on the state of an ancestor. - */ - public void requestRepaintAll(); - - /** - * Sets the parent connector of the connector. - * - * <p> - * This method automatically calls {@link #attach()} if the connector - * becomes attached to the application, regardless of whether it was - * attached previously. Conversely, if the parent is {@code null} and the - * connector is attached to the application, {@link #detach()} is called for - * the connector. - * </p> - * <p> - * This method is rarely called directly. One of the - * {@link ComponentContainer#addComponent(Component)} or - * {@link AbstractClientConnector#addExtension(Extension)} methods are - * normally used for adding connectors to a parent and they will call this - * method implicitly. - * </p> - * - * <p> - * It is not possible to change the parent without first setting the parent - * to {@code null}. - * </p> - * - * @param parent - * the parent connector - * @throws IllegalStateException - * if a parent is given even though the connector already has a - * parent - */ - public void setParent(ClientConnector parent); - - /** - * Notifies the connector that it is connected to an application. - * - * <p> - * The caller of this method is {@link #setParent(ClientConnector)} if the - * parent is itself already attached to the application. If not, the parent - * will call the {@link #attach()} for all its children when it is attached - * to the application. This method is always called before the connector's - * data is sent to the client-side for the first time. - * </p> - * - * <p> - * The attachment logic is implemented in {@link AbstractClientConnector}. - * </p> - */ - public void attach(); - - /** - * Notifies the component that it is detached from the application. - * - * <p> - * The caller of this method is {@link #setParent(ClientConnector)} if the - * parent is in the application. When the parent is detached from the - * application it is its response to call {@link #detach()} for all the - * children and to detach itself from the terminal. - * </p> - */ - public void detach(); - - /** - * Get a read-only collection of all extensions attached to this connector. - * - * @return a collection of extensions - */ - public Collection<Extension> getExtensions(); - - /** - * Remove an extension from this connector. - * - * @param extension - * the extension to remove. - */ - public void removeExtension(Extension extension); - - /** - * Returns the root this connector is attached to - * - * @return The Root this connector is attached to or null if it is not - * attached to any Root - */ - public Root getRoot(); -} diff --git a/src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java b/src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java deleted file mode 100644 index 64ea288665..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java +++ /dev/null @@ -1,71 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.Serializable; -import java.lang.reflect.Method; -import java.lang.reflect.Type; - -/** - * Internal class for keeping track of pending server to client method - * invocations for a Connector. - * - * @since 7.0 - */ -public class ClientMethodInvocation implements Serializable, - Comparable<ClientMethodInvocation> { - private final ClientConnector connector; - private final String interfaceName; - private final String methodName; - private final Object[] parameters; - private Type[] parameterTypes; - - // used for sorting calls between different connectors in the same Root - private final long sequenceNumber; - // TODO may cause problems when clustering etc. - private static long counter = 0; - - public ClientMethodInvocation(ClientConnector connector, - String interfaceName, Method method, Object[] parameters) { - this.connector = connector; - this.interfaceName = interfaceName; - methodName = method.getName(); - parameterTypes = method.getGenericParameterTypes(); - this.parameters = (null != parameters) ? parameters : new Object[0]; - sequenceNumber = ++counter; - } - - public Type[] getParameterTypes() { - return parameterTypes; - } - - public ClientConnector getConnector() { - return connector; - } - - public String getInterfaceName() { - return interfaceName; - } - - public String getMethodName() { - return methodName; - } - - public Object[] getParameters() { - return parameters; - } - - protected long getSequenceNumber() { - return sequenceNumber; - } - - @Override - public int compareTo(ClientMethodInvocation o) { - if (null == o) { - return 0; - } - return Long.signum(getSequenceNumber() - o.getSequenceNumber()); - } -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java b/src/com/vaadin/terminal/gwt/server/CommunicationManager.java deleted file mode 100644 index 3cc3a8cb64..0000000000 --- a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java +++ /dev/null @@ -1,122 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.InputStream; -import java.net.URL; - -import javax.servlet.ServletContext; - -import com.vaadin.Application; -import com.vaadin.external.json.JSONException; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.ui.Root; - -/** - * Application manager processes changes and paints for single application - * instance. - * - * This class handles applications running as servlets. - * - * @see AbstractCommunicationManager - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.0 - */ -@SuppressWarnings("serial") -public class CommunicationManager extends AbstractCommunicationManager { - - /** - * @deprecated use {@link #CommunicationManager(Application)} instead - * @param application - * @param applicationServlet - */ - @Deprecated - public CommunicationManager(Application application, - AbstractApplicationServlet applicationServlet) { - super(application); - } - - /** - * TODO New constructor - document me! - * - * @param application - */ - public CommunicationManager(Application application) { - super(application); - } - - @Override - protected BootstrapHandler createBootstrapHandler() { - return new BootstrapHandler() { - @Override - protected String getApplicationId(BootstrapContext context) { - String appUrl = getAppUri(context); - - String appId = appUrl; - if ("".equals(appUrl)) { - appId = "ROOT"; - } - appId = appId.replaceAll("[^a-zA-Z0-9]", ""); - // Add hashCode to the end, so that it is still (sort of) - // predictable, but indicates that it should not be used in CSS - // and - // such: - int hashCode = appId.hashCode(); - if (hashCode < 0) { - hashCode = -hashCode; - } - appId = appId + "-" + hashCode; - return appId; - } - - @Override - protected String getAppUri(BootstrapContext context) { - /* Fetch relative url to application */ - // don't use server and port in uri. It may cause problems with - // some - // virtual server configurations which lose the server name - Application application = context.getApplication(); - URL url = application.getURL(); - String appUrl = url.getPath(); - if (appUrl.endsWith("/")) { - appUrl = appUrl.substring(0, appUrl.length() - 1); - } - return appUrl; - } - - @Override - public String getThemeName(BootstrapContext context) { - String themeName = context.getRequest().getParameter( - AbstractApplicationServlet.URL_PARAMETER_THEME); - if (themeName == null) { - themeName = super.getThemeName(context); - } - return themeName; - } - - @Override - protected String getInitialUIDL(WrappedRequest request, Root root) - throws PaintException, JSONException { - return CommunicationManager.this.getInitialUIDL(request, root); - } - }; - } - - @Override - protected InputStream getThemeResourceAsStream(Root root, String themeName, - String resource) { - WebApplicationContext context = (WebApplicationContext) root - .getApplication().getContext(); - ServletContext servletContext = context.getHttpSession() - .getServletContext(); - return servletContext.getResourceAsStream("/" - + AbstractApplicationServlet.THEME_DIRECTORY_PATH + themeName - + "/" + resource); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/ComponentSizeValidator.java b/src/com/vaadin/terminal/gwt/server/ComponentSizeValidator.java deleted file mode 100644 index 171d440796..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ComponentSizeValidator.java +++ /dev/null @@ -1,664 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.PrintStream; -import java.io.PrintWriter; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Stack; -import java.util.Vector; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.vaadin.terminal.Sizeable.Unit; -import com.vaadin.ui.AbstractOrderedLayout; -import com.vaadin.ui.AbstractSplitPanel; -import com.vaadin.ui.Component; -import com.vaadin.ui.ComponentContainer; -import com.vaadin.ui.CustomComponent; -import com.vaadin.ui.Form; -import com.vaadin.ui.GridLayout; -import com.vaadin.ui.GridLayout.Area; -import com.vaadin.ui.Layout; -import com.vaadin.ui.Panel; -import com.vaadin.ui.TabSheet; -import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; - -@SuppressWarnings({ "serial", "deprecation" }) -public class ComponentSizeValidator implements Serializable { - - private final static int LAYERS_SHOWN = 4; - - /** - * Recursively checks given component and its subtree for invalid layout - * setups. Prints errors to std err stream. - * - * @param component - * component to check - * @return set of first level errors found - */ - public static List<InvalidLayout> validateComponentRelativeSizes( - Component component, List<InvalidLayout> errors, - InvalidLayout parent) { - - boolean invalidHeight = !checkHeights(component); - boolean invalidWidth = !checkWidths(component); - - if (invalidHeight || invalidWidth) { - InvalidLayout error = new InvalidLayout(component, invalidHeight, - invalidWidth); - if (parent != null) { - parent.addError(error); - } else { - if (errors == null) { - errors = new LinkedList<InvalidLayout>(); - } - errors.add(error); - } - parent = error; - } - - if (component instanceof Panel) { - Panel panel = (Panel) component; - errors = validateComponentRelativeSizes(panel.getContent(), errors, - parent); - } else if (component instanceof ComponentContainer) { - ComponentContainer lo = (ComponentContainer) component; - Iterator<Component> it = lo.getComponentIterator(); - while (it.hasNext()) { - errors = validateComponentRelativeSizes(it.next(), errors, - parent); - } - } else if (component instanceof Form) { - Form form = (Form) component; - if (form.getLayout() != null) { - errors = validateComponentRelativeSizes(form.getLayout(), - errors, parent); - } - if (form.getFooter() != null) { - errors = validateComponentRelativeSizes(form.getFooter(), - errors, parent); - } - } - - return errors; - } - - private static void printServerError(String msg, - Stack<ComponentInfo> attributes, boolean widthError, - PrintStream errorStream) { - StringBuffer err = new StringBuffer(); - err.append("Vaadin DEBUG\n"); - - StringBuilder indent = new StringBuilder(""); - ComponentInfo ci; - if (attributes != null) { - while (attributes.size() > LAYERS_SHOWN) { - attributes.pop(); - } - while (!attributes.empty()) { - ci = attributes.pop(); - showComponent(ci.component, ci.info, err, indent, widthError); - } - } - - err.append("Layout problem detected: "); - err.append(msg); - err.append("\n"); - err.append("Relative sizes were replaced by undefined sizes, components may not render as expected.\n"); - errorStream.println(err); - - } - - public static boolean checkHeights(Component component) { - try { - if (!hasRelativeHeight(component)) { - return true; - } - if (component instanceof Window) { - return true; - } - if (component.getParent() == null) { - return true; - } - - return parentCanDefineHeight(component); - } catch (Exception e) { - getLogger().log(Level.FINER, - "An exception occurred while validating sizes.", e); - return true; - } - } - - public static boolean checkWidths(Component component) { - try { - if (!hasRelativeWidth(component)) { - return true; - } - if (component instanceof Window) { - return true; - } - if (component.getParent() == null) { - return true; - } - - return parentCanDefineWidth(component); - } catch (Exception e) { - getLogger().log(Level.FINER, - "An exception occurred while validating sizes.", e); - return true; - } - } - - public static class InvalidLayout implements Serializable { - - private final Component component; - - private final boolean invalidHeight; - private final boolean invalidWidth; - - private final Vector<InvalidLayout> subErrors = new Vector<InvalidLayout>(); - - public InvalidLayout(Component component, boolean height, boolean width) { - this.component = component; - invalidHeight = height; - invalidWidth = width; - } - - public void addError(InvalidLayout error) { - subErrors.add(error); - } - - public void reportErrors(PrintWriter clientJSON, - AbstractCommunicationManager communicationManager, - PrintStream serverErrorStream) { - clientJSON.write("{"); - - Component parent = component.getParent(); - String paintableId = component.getConnectorId(); - - clientJSON.print("id:\"" + paintableId + "\""); - - if (invalidHeight) { - Stack<ComponentInfo> attributes = null; - String msg = ""; - // set proper error messages - if (parent instanceof AbstractOrderedLayout) { - AbstractOrderedLayout ol = (AbstractOrderedLayout) parent; - boolean vertical = false; - - if (ol instanceof VerticalLayout) { - vertical = true; - } - - if (vertical) { - msg = "Component with relative height inside a VerticalLayout with no height defined."; - attributes = getHeightAttributes(component); - } else { - msg = "At least one of a HorizontalLayout's components must have non relative height if the height of the layout is not defined"; - attributes = getHeightAttributes(component); - } - } else if (parent instanceof GridLayout) { - msg = "At least one of the GridLayout's components in each row should have non relative height if the height of the layout is not defined."; - attributes = getHeightAttributes(component); - } else { - // default error for non sized parent issue - msg = "A component with relative height needs a parent with defined height."; - attributes = getHeightAttributes(component); - } - printServerError(msg, attributes, false, serverErrorStream); - clientJSON.print(",\"heightMsg\":\"" + msg + "\""); - } - if (invalidWidth) { - Stack<ComponentInfo> attributes = null; - String msg = ""; - if (parent instanceof AbstractOrderedLayout) { - AbstractOrderedLayout ol = (AbstractOrderedLayout) parent; - boolean horizontal = true; - - if (ol instanceof VerticalLayout) { - horizontal = false; - } - - if (horizontal) { - msg = "Component with relative width inside a HorizontalLayout with no width defined"; - attributes = getWidthAttributes(component); - } else { - msg = "At least one of a VerticalLayout's components must have non relative width if the width of the layout is not defined"; - attributes = getWidthAttributes(component); - } - } else if (parent instanceof GridLayout) { - msg = "At least one of the GridLayout's components in each column should have non relative width if the width of the layout is not defined."; - attributes = getWidthAttributes(component); - } else { - // default error for non sized parent issue - msg = "A component with relative width needs a parent with defined width."; - attributes = getWidthAttributes(component); - } - clientJSON.print(",\"widthMsg\":\"" + msg + "\""); - printServerError(msg, attributes, true, serverErrorStream); - } - if (subErrors.size() > 0) { - serverErrorStream.println("Sub errors >>"); - clientJSON.write(", \"subErrors\" : ["); - boolean first = true; - for (InvalidLayout subError : subErrors) { - if (!first) { - clientJSON.print(","); - } else { - first = false; - } - subError.reportErrors(clientJSON, communicationManager, - serverErrorStream); - } - clientJSON.write("]"); - serverErrorStream.println("<< Sub erros"); - } - clientJSON.write("}"); - } - } - - private static class ComponentInfo implements Serializable { - Component component; - String info; - - public ComponentInfo(Component component, String info) { - this.component = component; - this.info = info; - } - - } - - private static Stack<ComponentInfo> getHeightAttributes(Component component) { - Stack<ComponentInfo> attributes = new Stack<ComponentInfo>(); - attributes - .add(new ComponentInfo(component, getHeightString(component))); - Component parent = component.getParent(); - attributes.add(new ComponentInfo(parent, getHeightString(parent))); - - while ((parent = parent.getParent()) != null) { - attributes.add(new ComponentInfo(parent, getHeightString(parent))); - } - - return attributes; - } - - private static Stack<ComponentInfo> getWidthAttributes(Component component) { - Stack<ComponentInfo> attributes = new Stack<ComponentInfo>(); - attributes.add(new ComponentInfo(component, getWidthString(component))); - Component parent = component.getParent(); - attributes.add(new ComponentInfo(parent, getWidthString(parent))); - - while ((parent = parent.getParent()) != null) { - attributes.add(new ComponentInfo(parent, getWidthString(parent))); - } - - return attributes; - } - - private static String getWidthString(Component component) { - String width = "width: "; - if (hasRelativeWidth(component)) { - width += "RELATIVE, " + component.getWidth() + " %"; - } else if (component instanceof Window && component.getParent() == null) { - width += "MAIN WINDOW"; - } else if (component.getWidth() >= 0) { - width += "ABSOLUTE, " + component.getWidth() + " " - + component.getWidthUnits().getSymbol(); - } else { - width += "UNDEFINED"; - } - - return width; - } - - private static String getHeightString(Component component) { - String height = "height: "; - if (hasRelativeHeight(component)) { - height += "RELATIVE, " + component.getHeight() + " %"; - } else if (component instanceof Window && component.getParent() == null) { - height += "MAIN WINDOW"; - } else if (component.getHeight() > 0) { - height += "ABSOLUTE, " + component.getHeight() + " " - + component.getHeightUnits().getSymbol(); - } else { - height += "UNDEFINED"; - } - - return height; - } - - private static void showComponent(Component component, String attribute, - StringBuffer err, StringBuilder indent, boolean widthError) { - - FileLocation createLoc = creationLocations.get(component); - - FileLocation sizeLoc; - if (widthError) { - sizeLoc = widthLocations.get(component); - } else { - sizeLoc = heightLocations.get(component); - } - - err.append(indent); - indent.append(" "); - err.append("- "); - - err.append(component.getClass().getSimpleName()); - err.append("/").append(Integer.toHexString(component.hashCode())); - - if (component.getCaption() != null) { - err.append(" \""); - err.append(component.getCaption()); - err.append("\""); - } - - if (component.getDebugId() != null) { - err.append(" debugId: "); - err.append(component.getDebugId()); - } - - if (createLoc != null) { - err.append(", created at (" + createLoc.file + ":" - + createLoc.lineNumber + ")"); - - } - - if (attribute != null) { - err.append(" ("); - err.append(attribute); - if (sizeLoc != null) { - err.append(", set at (" + sizeLoc.file + ":" - + sizeLoc.lineNumber + ")"); - } - - err.append(")"); - } - err.append("\n"); - - } - - private static boolean hasNonRelativeHeightComponent( - AbstractOrderedLayout ol) { - Iterator<Component> it = ol.getComponentIterator(); - while (it.hasNext()) { - if (!hasRelativeHeight(it.next())) { - return true; - } - } - return false; - } - - public static boolean parentCanDefineHeight(Component component) { - Component parent = component.getParent(); - if (parent == null) { - // main window, valid situation - return true; - } - if (parent.getHeight() < 0) { - // Undefined height - if (parent instanceof Window) { - // Sub window with undefined size has a min-height - return true; - } - - if (parent instanceof AbstractOrderedLayout) { - boolean horizontal = true; - if (parent instanceof VerticalLayout) { - horizontal = false; - } - if (horizontal - && hasNonRelativeHeightComponent((AbstractOrderedLayout) parent)) { - return true; - } else { - return false; - } - - } else if (parent instanceof GridLayout) { - GridLayout gl = (GridLayout) parent; - Area componentArea = gl.getComponentArea(component); - boolean rowHasHeight = false; - for (int row = componentArea.getRow1(); !rowHasHeight - && row <= componentArea.getRow2(); row++) { - for (int column = 0; !rowHasHeight - && column < gl.getColumns(); column++) { - Component c = gl.getComponent(column, row); - if (c != null) { - rowHasHeight = !hasRelativeHeight(c); - } - } - } - if (!rowHasHeight) { - return false; - } else { - // Other components define row height - return true; - } - } - - if (parent instanceof Panel || parent instanceof AbstractSplitPanel - || parent instanceof TabSheet - || parent instanceof CustomComponent) { - // height undefined, we know how how component works and no - // exceptions - // TODO horiz SplitPanel ?? - return false; - } else { - // We cannot generally know if undefined component can serve - // space for children (like CustomLayout or component built by - // third party) so we assume they can - return true; - } - - } else if (hasRelativeHeight(parent)) { - // Relative height - if (parent.getParent() != null) { - return parentCanDefineHeight(parent); - } else { - return true; - } - } else { - // Absolute height - return true; - } - } - - private static boolean hasRelativeHeight(Component component) { - return (component.getHeightUnits() == Unit.PERCENTAGE && component - .getHeight() > 0); - } - - private static boolean hasNonRelativeWidthComponent(AbstractOrderedLayout ol) { - Iterator<Component> it = ol.getComponentIterator(); - while (it.hasNext()) { - if (!hasRelativeWidth(it.next())) { - return true; - } - } - return false; - } - - private static boolean hasRelativeWidth(Component paintable) { - return paintable.getWidth() > 0 - && paintable.getWidthUnits() == Unit.PERCENTAGE; - } - - public static boolean parentCanDefineWidth(Component component) { - Component parent = component.getParent(); - if (parent == null) { - // main window, valid situation - return true; - } - if (parent instanceof Window) { - // Sub window with undefined size has a min-width - return true; - } - - if (parent.getWidth() < 0) { - // Undefined width - - if (parent instanceof AbstractOrderedLayout) { - AbstractOrderedLayout ol = (AbstractOrderedLayout) parent; - boolean horizontal = true; - if (ol instanceof VerticalLayout) { - horizontal = false; - } - - if (!horizontal && hasNonRelativeWidthComponent(ol)) { - // valid situation, other components defined width - return true; - } else { - return false; - } - } else if (parent instanceof GridLayout) { - GridLayout gl = (GridLayout) parent; - Area componentArea = gl.getComponentArea(component); - boolean columnHasWidth = false; - for (int col = componentArea.getColumn1(); !columnHasWidth - && col <= componentArea.getColumn2(); col++) { - for (int row = 0; !columnHasWidth && row < gl.getRows(); row++) { - Component c = gl.getComponent(col, row); - if (c != null) { - columnHasWidth = !hasRelativeWidth(c); - } - } - } - if (!columnHasWidth) { - return false; - } else { - // Other components define column width - return true; - } - } else if (parent instanceof Form) { - /* - * If some other part of the form is not relative it determines - * the component width - */ - return hasNonRelativeWidthComponent((Form) parent); - } else if (parent instanceof AbstractSplitPanel - || parent instanceof TabSheet - || parent instanceof CustomComponent) { - // FIXME Could we use com.vaadin package name here and - // fail for all component containers? - // FIXME Actually this should be moved to containers so it can - // be implemented for custom containers - // TODO vertical splitpanel with another non relative component? - return false; - } else if (parent instanceof Window) { - // Sub window can define width based on caption - if (parent.getCaption() != null - && !parent.getCaption().equals("")) { - return true; - } else { - return false; - } - } else if (parent instanceof Panel) { - // TODO Panel should be able to define width based on caption - return false; - } else { - return true; - } - } else if (hasRelativeWidth(parent)) { - // Relative width - if (parent.getParent() == null) { - return true; - } - - return parentCanDefineWidth(parent); - } else { - return true; - } - - } - - private static boolean hasNonRelativeWidthComponent(Form form) { - Layout layout = form.getLayout(); - Layout footer = form.getFooter(); - - if (layout != null && !hasRelativeWidth(layout)) { - return true; - } - if (footer != null && !hasRelativeWidth(footer)) { - return true; - } - - return false; - } - - private static Map<Object, FileLocation> creationLocations = new HashMap<Object, FileLocation>(); - private static Map<Object, FileLocation> widthLocations = new HashMap<Object, FileLocation>(); - private static Map<Object, FileLocation> heightLocations = new HashMap<Object, FileLocation>(); - - public static class FileLocation implements Serializable { - public String method; - public String file; - public String className; - public String classNameSimple; - public int lineNumber; - - public FileLocation(StackTraceElement traceElement) { - file = traceElement.getFileName(); - className = traceElement.getClassName(); - classNameSimple = className - .substring(className.lastIndexOf('.') + 1); - lineNumber = traceElement.getLineNumber(); - method = traceElement.getMethodName(); - } - } - - public static void setCreationLocation(Object object) { - setLocation(creationLocations, object); - } - - public static void setWidthLocation(Object object) { - setLocation(widthLocations, object); - } - - public static void setHeightLocation(Object object) { - setLocation(heightLocations, object); - } - - private static void setLocation(Map<Object, FileLocation> map, Object object) { - StackTraceElement[] traceLines = Thread.currentThread().getStackTrace(); - for (StackTraceElement traceElement : traceLines) { - Class<?> cls; - try { - String className = traceElement.getClassName(); - if (className.startsWith("java.") - || className.startsWith("sun.")) { - continue; - } - - cls = Class.forName(className); - if (cls == ComponentSizeValidator.class || cls == Thread.class) { - continue; - } - - if (Component.class.isAssignableFrom(cls) - && !CustomComponent.class.isAssignableFrom(cls)) { - continue; - } - FileLocation cl = new FileLocation(traceElement); - map.put(object, cl); - return; - } catch (Exception e) { - // TODO Auto-generated catch block - getLogger().log(Level.FINER, - "An exception occurred while validating sizes.", e); - } - - } - } - - private static Logger getLogger() { - return Logger.getLogger(ComponentSizeValidator.class.getName()); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/Constants.java b/src/com/vaadin/terminal/gwt/server/Constants.java deleted file mode 100644 index 7efb0205ac..0000000000 --- a/src/com/vaadin/terminal/gwt/server/Constants.java +++ /dev/null @@ -1,80 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -/** - * TODO Document me! - * - * @author peholmst - * - */ -public interface Constants { - - static final String NOT_PRODUCTION_MODE_INFO = "\n" - + "=================================================================\n" - + "Vaadin is running in DEBUG MODE.\nAdd productionMode=true to web.xml " - + "to disable debug features.\nTo show debug window, add ?debug to " - + "your application URL.\n" - + "================================================================="; - - static final String WARNING_XSRF_PROTECTION_DISABLED = "\n" - + "===========================================================\n" - + "WARNING: Cross-site request forgery protection is disabled!\n" - + "==========================================================="; - - static final String WARNING_RESOURCE_CACHING_TIME_NOT_NUMERIC = "\n" - + "===========================================================\n" - + "WARNING: resourceCacheTime has been set to a non integer value " - + "in web.xml. The default of 1h will be used.\n" - + "==========================================================="; - - static final String WIDGETSET_MISMATCH_INFO = "\n" - + "=================================================================\n" - + "The widgetset in use does not seem to be built for the Vaadin\n" - + "version in use. This might cause strange problems - a\n" - + "recompile/deploy is strongly recommended.\n" - + " Vaadin version: %s\n" - + " Widgetset version: %s\n" - + "================================================================="; - - static final String URL_PARAMETER_RESTART_APPLICATION = "restartApplication"; - static final String URL_PARAMETER_CLOSE_APPLICATION = "closeApplication"; - static final String URL_PARAMETER_REPAINT_ALL = "repaintAll"; - static final String URL_PARAMETER_THEME = "theme"; - - static final String SERVLET_PARAMETER_PRODUCTION_MODE = "productionMode"; - static final String SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION = "disable-xsrf-protection"; - static final String SERVLET_PARAMETER_RESOURCE_CACHE_TIME = "resourceCacheTime"; - - // Configurable parameter names - static final String PARAMETER_VAADIN_RESOURCES = "Resources"; - - static final int DEFAULT_BUFFER_SIZE = 32 * 1024; - - static final int MAX_BUFFER_SIZE = 64 * 1024; - - final String THEME_DIRECTORY_PATH = "VAADIN/themes/"; - - static final int DEFAULT_THEME_CACHETIME = 1000 * 60 * 60 * 24; - - static final String WIDGETSET_DIRECTORY_PATH = "VAADIN/widgetsets/"; - - // Name of the default widget set, used if not specified in web.xml - static final String DEFAULT_WIDGETSET = "com.vaadin.terminal.gwt.DefaultWidgetSet"; - - // Widget set parameter name - static final String PARAMETER_WIDGETSET = "widgetset"; - - static final String ERROR_NO_ROOT_FOUND = "Application did not return a root for the request and did not request extra information either. Something is wrong."; - - static final String DEFAULT_THEME_NAME = "reindeer"; - - static final String INVALID_SECURITY_KEY_MSG = "Invalid security key."; - - // portal configuration parameters - static final String PORTAL_PARAMETER_VAADIN_WIDGETSET = "vaadin.widgetset"; - static final String PORTAL_PARAMETER_VAADIN_RESOURCE_PATH = "vaadin.resources.path"; - static final String PORTAL_PARAMETER_VAADIN_THEME = "vaadin.theme"; - -} diff --git a/src/com/vaadin/terminal/gwt/server/DragAndDropService.java b/src/com/vaadin/terminal/gwt/server/DragAndDropService.java deleted file mode 100644 index efb5666efa..0000000000 --- a/src/com/vaadin/terminal/gwt/server/DragAndDropService.java +++ /dev/null @@ -1,313 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.PrintWriter; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.logging.Logger; - -import com.vaadin.event.Transferable; -import com.vaadin.event.TransferableImpl; -import com.vaadin.event.dd.DragAndDropEvent; -import com.vaadin.event.dd.DragSource; -import com.vaadin.event.dd.DropHandler; -import com.vaadin.event.dd.DropTarget; -import com.vaadin.event.dd.TargetDetails; -import com.vaadin.event.dd.TargetDetailsImpl; -import com.vaadin.event.dd.acceptcriteria.AcceptCriterion; -import com.vaadin.shared.communication.SharedState; -import com.vaadin.shared.ui.dd.DragEventType; -import com.vaadin.terminal.Extension; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.VariableOwner; -import com.vaadin.terminal.gwt.client.ui.dd.VDragAndDropManager; -import com.vaadin.ui.Component; -import com.vaadin.ui.Root; - -public class DragAndDropService implements VariableOwner, ClientConnector { - - private int lastVisitId; - - private boolean lastVisitAccepted = false; - - private DragAndDropEvent dragEvent; - - private final AbstractCommunicationManager manager; - - private AcceptCriterion acceptCriterion; - - public DragAndDropService(AbstractCommunicationManager manager) { - this.manager = manager; - } - - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - Object owner = variables.get("dhowner"); - - // Validate drop handler owner - if (!(owner instanceof DropTarget)) { - getLogger() - .severe("DropHandler owner " + owner - + " must implement DropTarget"); - return; - } - // owner cannot be null here - - DropTarget dropTarget = (DropTarget) owner; - lastVisitId = (Integer) variables.get("visitId"); - - // request may be dropRequest or request during drag operation (commonly - // dragover or dragenter) - boolean dropRequest = isDropRequest(variables); - if (dropRequest) { - handleDropRequest(dropTarget, variables); - } else { - handleDragRequest(dropTarget, variables); - } - - } - - /** - * Handles a drop request from the VDragAndDropManager. - * - * @param dropTarget - * @param variables - */ - private void handleDropRequest(DropTarget dropTarget, - Map<String, Object> variables) { - DropHandler dropHandler = (dropTarget).getDropHandler(); - if (dropHandler == null) { - // No dropHandler returned so no drop can be performed. - getLogger().fine( - "DropTarget.getDropHandler() returned null for owner: " - + dropTarget); - return; - } - - /* - * Construct the Transferable and the DragDropDetails for the drop - * operation based on the info passed from the client widgets (drag - * source for Transferable, drop target for DragDropDetails). - */ - Transferable transferable = constructTransferable(dropTarget, variables); - TargetDetails dropData = constructDragDropDetails(dropTarget, variables); - DragAndDropEvent dropEvent = new DragAndDropEvent(transferable, - dropData); - if (dropHandler.getAcceptCriterion().accept(dropEvent)) { - dropHandler.drop(dropEvent); - } - } - - /** - * Handles a drag/move request from the VDragAndDropManager. - * - * @param dropTarget - * @param variables - */ - private void handleDragRequest(DropTarget dropTarget, - Map<String, Object> variables) { - lastVisitId = (Integer) variables.get("visitId"); - - acceptCriterion = dropTarget.getDropHandler().getAcceptCriterion(); - - /* - * Construct the Transferable and the DragDropDetails for the drag - * operation based on the info passed from the client widgets (drag - * source for Transferable, current target for DragDropDetails). - */ - Transferable transferable = constructTransferable(dropTarget, variables); - TargetDetails dragDropDetails = constructDragDropDetails(dropTarget, - variables); - - dragEvent = new DragAndDropEvent(transferable, dragDropDetails); - - lastVisitAccepted = acceptCriterion.accept(dragEvent); - } - - /** - * Construct DragDropDetails based on variables from client drop target. - * Uses DragDropDetailsTranslator if available, otherwise a default - * DragDropDetails implementation is used. - * - * @param dropTarget - * @param variables - * @return - */ - @SuppressWarnings("unchecked") - private TargetDetails constructDragDropDetails(DropTarget dropTarget, - Map<String, Object> variables) { - Map<String, Object> rawDragDropDetails = (Map<String, Object>) variables - .get("evt"); - - TargetDetails dropData = dropTarget - .translateDropTargetDetails(rawDragDropDetails); - - if (dropData == null) { - // Create a default DragDropDetails with all the raw variables - dropData = new TargetDetailsImpl(rawDragDropDetails, dropTarget); - } - - return dropData; - } - - private boolean isDropRequest(Map<String, Object> variables) { - return getRequestType(variables) == DragEventType.DROP; - } - - private DragEventType getRequestType(Map<String, Object> variables) { - int type = (Integer) variables.get("type"); - return DragEventType.values()[type]; - } - - @SuppressWarnings("unchecked") - private Transferable constructTransferable(DropTarget dropHandlerOwner, - Map<String, Object> variables) { - final Component sourceComponent = (Component) variables - .get("component"); - - variables = (Map<String, Object>) variables.get("tra"); - - Transferable transferable = null; - if (sourceComponent != null && sourceComponent instanceof DragSource) { - transferable = ((DragSource) sourceComponent) - .getTransferable(variables); - } - if (transferable == null) { - transferable = new TransferableImpl(sourceComponent, variables); - } - - return transferable; - } - - @Override - public boolean isEnabled() { - return isConnectorEnabled(); - } - - @Override - public boolean isImmediate() { - return true; - } - - void printJSONResponse(PrintWriter outWriter) throws PaintException { - if (isDirty()) { - - outWriter.print(", \"dd\":"); - - JsonPaintTarget jsonPaintTarget = new JsonPaintTarget(manager, - outWriter, false); - jsonPaintTarget.startTag("dd"); - jsonPaintTarget.addAttribute("visitId", lastVisitId); - if (acceptCriterion != null) { - jsonPaintTarget.addAttribute("accepted", lastVisitAccepted); - acceptCriterion.paintResponse(jsonPaintTarget); - } - jsonPaintTarget.endTag("dd"); - jsonPaintTarget.close(); - lastVisitId = -1; - lastVisitAccepted = false; - acceptCriterion = null; - dragEvent = null; - } - } - - private boolean isDirty() { - if (lastVisitId > 0) { - return true; - } - return false; - } - - @Override - public SharedState getState() { - // TODO Auto-generated method stub - return null; - } - - @Override - public String getConnectorId() { - return VDragAndDropManager.DD_SERVICE; - } - - @Override - public boolean isConnectorEnabled() { - // Drag'n'drop can't be disabled - return true; - } - - @Override - public List<ClientMethodInvocation> retrievePendingRpcCalls() { - return null; - } - - @Override - public RpcManager getRpcManager(Class<?> rpcInterface) { - // TODO Use rpc for drag'n'drop - return null; - } - - @Override - public Class<? extends SharedState> getStateType() { - return SharedState.class; - } - - @Override - public void requestRepaint() { - // TODO Auto-generated method stub - - } - - @Override - public ClientConnector getParent() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void requestRepaintAll() { - // TODO Auto-generated method stub - - } - - @Override - public void setParent(ClientConnector parent) { - // TODO Auto-generated method stub - - } - - @Override - public void attach() { - // TODO Auto-generated method stub - - } - - @Override - public void detach() { - // TODO Auto-generated method stub - - } - - @Override - public Collection<Extension> getExtensions() { - // TODO Auto-generated method stub - return Collections.emptySet(); - } - - @Override - public void removeExtension(Extension extension) { - // TODO Auto-generated method stub - } - - private Logger getLogger() { - return Logger.getLogger(DragAndDropService.class.getName()); - } - - @Override - public Root getRoot() { - return null; - } -} diff --git a/src/com/vaadin/terminal/gwt/server/GAEApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/GAEApplicationServlet.java deleted file mode 100644 index cc12c9cc43..0000000000 --- a/src/com/vaadin/terminal/gwt/server/GAEApplicationServlet.java +++ /dev/null @@ -1,417 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.NotSerializableException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import com.google.appengine.api.datastore.Blob; -import com.google.appengine.api.datastore.DatastoreService; -import com.google.appengine.api.datastore.DatastoreServiceFactory; -import com.google.appengine.api.datastore.Entity; -import com.google.appengine.api.datastore.EntityNotFoundException; -import com.google.appengine.api.datastore.FetchOptions.Builder; -import com.google.appengine.api.datastore.Key; -import com.google.appengine.api.datastore.KeyFactory; -import com.google.appengine.api.datastore.PreparedQuery; -import com.google.appengine.api.datastore.Query; -import com.google.appengine.api.datastore.Query.FilterOperator; -import com.google.appengine.api.memcache.Expiration; -import com.google.appengine.api.memcache.MemcacheService; -import com.google.appengine.api.memcache.MemcacheServiceFactory; -import com.google.apphosting.api.DeadlineExceededException; -import com.vaadin.service.ApplicationContext; - -/** - * ApplicationServlet to be used when deploying to Google App Engine, in - * web.xml: - * - * <pre> - * <servlet> - * <servlet-name>HelloWorld</servlet-name> - * <servlet-class>com.vaadin.terminal.gwt.server.GAEApplicationServlet</servlet-class> - * <init-param> - * <param-name>application</param-name> - * <param-value>com.vaadin.demo.HelloWorld</param-value> - * </init-param> - * </servlet> - * </pre> - * - * Session support must be enabled in appengine-web.xml: - * - * <pre> - * <sessions-enabled>true</sessions-enabled> - * </pre> - * - * Appengine datastore cleanup can be invoked by calling one of the applications - * with an additional path "/CLEAN". This can be set up as a cron-job in - * cron.xml (see appengine documentation for more information): - * - * <pre> - * <cronentries> - * <cron> - * <url>/HelloWorld/CLEAN</url> - * <description>Clean up sessions</description> - * <schedule>every 2 hours</schedule> - * </cron> - * </cronentries> - * </pre> - * - * It is recommended (but not mandatory) to extract themes and widgetsets and - * have App Engine server these statically. Extract VAADIN folder (and it's - * contents) 'next to' the WEB-INF folder, and add the following to - * appengine-web.xml: - * - * <pre> - * <static-files> - * <include path="/VAADIN/**" /> - * </static-files> - * </pre> - * - * Additional limitations: - * <ul> - * <li/>Do not change application state when serving an ApplicationResource. - * <li/>Avoid changing application state in transaction handlers, unless you're - * confident you fully understand the synchronization issues in App Engine. - * <li/>The application remains locked while uploading - no progressbar is - * possible. - * </ul> - */ -public class GAEApplicationServlet extends ApplicationServlet { - - // memcache mutex is MUTEX_BASE + sessio id - private static final String MUTEX_BASE = "_vmutex"; - - // used identify ApplicationContext in memcache and datastore - private static final String AC_BASE = "_vac"; - - // UIDL requests will attempt to gain access for this long before telling - // the client to retry - private static final int MAX_UIDL_WAIT_MILLISECONDS = 5000; - - // Tell client to retry after this delay. - // Note: currently interpreting Retry-After as ms, not sec - private static final int RETRY_AFTER_MILLISECONDS = 100; - - // Properties used in the datastore - private static final String PROPERTY_EXPIRES = "expires"; - private static final String PROPERTY_DATA = "data"; - - // path used for cleanup - private static final String CLEANUP_PATH = "/CLEAN"; - // max entities to clean at once - private static final int CLEANUP_LIMIT = 200; - // appengine session kind - private static final String APPENGINE_SESSION_KIND = "_ah_SESSION"; - // appengine session expires-parameter - private static final String PROPERTY_APPENGINE_EXPIRES = "_expires"; - - protected void sendDeadlineExceededNotification( - WrappedHttpServletRequest request, - WrappedHttpServletResponse response) throws IOException { - criticalNotification( - request, - response, - "Deadline Exceeded", - "I'm sorry, but the operation took too long to complete. We'll try reloading to see where we're at, please take note of any unsaved data...", - "", null); - } - - protected void sendNotSerializableNotification( - WrappedHttpServletRequest request, - WrappedHttpServletResponse response) throws IOException { - criticalNotification( - request, - response, - "NotSerializableException", - "I'm sorry, but there seems to be a serious problem, please contact the administrator. And please take note of any unsaved data...", - "", getApplicationUrl(request).toString() - + "?restartApplication"); - } - - protected void sendCriticalErrorNotification( - WrappedHttpServletRequest request, - WrappedHttpServletResponse response) throws IOException { - criticalNotification( - request, - response, - "Critical error", - "I'm sorry, but there seems to be a serious problem, please contact the administrator. And please take note of any unsaved data...", - "", getApplicationUrl(request).toString() - + "?restartApplication"); - } - - @Override - protected void service(HttpServletRequest unwrappedRequest, - HttpServletResponse unwrappedResponse) throws ServletException, - IOException { - WrappedHttpServletRequest request = new WrappedHttpServletRequest( - unwrappedRequest, getDeploymentConfiguration()); - WrappedHttpServletResponse response = new WrappedHttpServletResponse( - unwrappedResponse, getDeploymentConfiguration()); - - if (isCleanupRequest(request)) { - cleanDatastore(); - return; - } - - RequestType requestType = getRequestType(request); - - if (requestType == RequestType.STATIC_FILE) { - // no locking needed, let superclass handle - super.service(request, response); - cleanSession(request); - return; - } - - if (requestType == RequestType.APPLICATION_RESOURCE) { - // no locking needed, let superclass handle - getApplicationContext(request, - MemcacheServiceFactory.getMemcacheService()); - super.service(request, response); - cleanSession(request); - return; - } - - final HttpSession session = request - .getSession(requestCanCreateApplication(request, requestType)); - if (session == null) { - handleServiceSessionExpired(request, response); - cleanSession(request); - return; - } - - boolean locked = false; - MemcacheService memcache = null; - String mutex = MUTEX_BASE + session.getId(); - memcache = MemcacheServiceFactory.getMemcacheService(); - try { - // try to get lock - long started = new Date().getTime(); - // non-UIDL requests will try indefinitely - while (requestType != RequestType.UIDL - || new Date().getTime() - started < MAX_UIDL_WAIT_MILLISECONDS) { - locked = memcache.put(mutex, 1, Expiration.byDeltaSeconds(40), - MemcacheService.SetPolicy.ADD_ONLY_IF_NOT_PRESENT); - if (locked) { - break; - } - try { - Thread.sleep(RETRY_AFTER_MILLISECONDS); - } catch (InterruptedException e) { - getLogger().finer( - "Thread.sleep() interrupted while waiting for lock. Trying again. " - + e); - } - } - - if (!locked) { - // Not locked; only UIDL can get trough here unlocked: tell - // client to retry - response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE); - // Note: currently interpreting Retry-After as ms, not sec - response.setHeader("Retry-After", "" + RETRY_AFTER_MILLISECONDS); - return; - } - - // de-serialize or create application context, store in session - ApplicationContext ctx = getApplicationContext(request, memcache); - - super.service(request, response); - - // serialize - started = new Date().getTime(); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(ctx); - oos.flush(); - byte[] bytes = baos.toByteArray(); - - started = new Date().getTime(); - - String id = AC_BASE + session.getId(); - Date expire = new Date(started - + (session.getMaxInactiveInterval() * 1000)); - Expiration expires = Expiration.onDate(expire); - - memcache.put(id, bytes, expires); - - DatastoreService ds = DatastoreServiceFactory.getDatastoreService(); - Entity entity = new Entity(AC_BASE, id); - entity.setProperty(PROPERTY_EXPIRES, expire.getTime()); - entity.setProperty(PROPERTY_DATA, new Blob(bytes)); - ds.put(entity); - - } catch (DeadlineExceededException e) { - getLogger().warning("DeadlineExceeded for " + session.getId()); - sendDeadlineExceededNotification(request, response); - } catch (NotSerializableException e) { - getLogger().log(Level.SEVERE, "Not serializable!", e); - - // TODO this notification is usually not shown - should we redirect - // in some other way - can we? - sendNotSerializableNotification(request, response); - } catch (Exception e) { - getLogger().log(Level.WARNING, - "An exception occurred while servicing request.", e); - - sendCriticalErrorNotification(request, response); - } finally { - // "Next, please!" - if (locked) { - memcache.delete(mutex); - } - cleanSession(request); - } - } - - protected ApplicationContext getApplicationContext( - HttpServletRequest request, MemcacheService memcache) { - HttpSession session = request.getSession(); - String id = AC_BASE + session.getId(); - byte[] serializedAC = (byte[]) memcache.get(id); - if (serializedAC == null) { - DatastoreService ds = DatastoreServiceFactory.getDatastoreService(); - Key key = KeyFactory.createKey(AC_BASE, id); - Entity entity = null; - try { - entity = ds.get(key); - } catch (EntityNotFoundException e) { - // Ok, we were a bit optimistic; we'll create a new one later - } - if (entity != null) { - Blob blob = (Blob) entity.getProperty(PROPERTY_DATA); - serializedAC = blob.getBytes(); - // bring it to memcache - memcache.put(AC_BASE + session.getId(), serializedAC, - Expiration.byDeltaSeconds(session - .getMaxInactiveInterval()), - MemcacheService.SetPolicy.ADD_ONLY_IF_NOT_PRESENT); - } - } - if (serializedAC != null) { - ByteArrayInputStream bais = new ByteArrayInputStream(serializedAC); - ObjectInputStream ois; - try { - ois = new ObjectInputStream(bais); - ApplicationContext applicationContext = (ApplicationContext) ois - .readObject(); - session.setAttribute(WebApplicationContext.class.getName(), - applicationContext); - } catch (IOException e) { - getLogger().log( - Level.WARNING, - "Could not de-serialize ApplicationContext for " - + session.getId() - + " A new one will be created. ", e); - } catch (ClassNotFoundException e) { - getLogger().log( - Level.WARNING, - "Could not de-serialize ApplicationContext for " - + session.getId() - + " A new one will be created. ", e); - } - } - // will create new context if the above did not - return getApplicationContext(session); - - } - - private boolean isCleanupRequest(HttpServletRequest request) { - String path = getRequestPathInfo(request); - if (path != null && path.equals(CLEANUP_PATH)) { - return true; - } - return false; - } - - /** - * Removes the ApplicationContext from the session in order to minimize the - * data serialized to datastore and memcache. - * - * @param request - */ - private void cleanSession(HttpServletRequest request) { - HttpSession session = request.getSession(false); - if (session != null) { - session.removeAttribute(WebApplicationContext.class.getName()); - } - } - - /** - * This will look at the timestamp and delete expired persisted Vaadin and - * appengine sessions from the datastore. - * - * TODO Possible improvements include: 1. Use transactions (requires entity - * groups - overkill?) 2. Delete one-at-a-time, catch possible exception, - * continue w/ next. - */ - private void cleanDatastore() { - long expire = new Date().getTime(); - try { - DatastoreService ds = DatastoreServiceFactory.getDatastoreService(); - // Vaadin stuff first - { - Query q = new Query(AC_BASE); - q.setKeysOnly(); - - q.addFilter(PROPERTY_EXPIRES, - FilterOperator.LESS_THAN_OR_EQUAL, expire); - PreparedQuery pq = ds.prepare(q); - List<Entity> entities = pq.asList(Builder - .withLimit(CLEANUP_LIMIT)); - if (entities != null) { - getLogger().info( - "Vaadin cleanup deleting " + entities.size() - + " expired Vaadin sessions."); - List<Key> keys = new ArrayList<Key>(); - for (Entity e : entities) { - keys.add(e.getKey()); - } - ds.delete(keys); - } - } - // Also cleanup GAE sessions - { - Query q = new Query(APPENGINE_SESSION_KIND); - q.setKeysOnly(); - q.addFilter(PROPERTY_APPENGINE_EXPIRES, - FilterOperator.LESS_THAN_OR_EQUAL, expire); - PreparedQuery pq = ds.prepare(q); - List<Entity> entities = pq.asList(Builder - .withLimit(CLEANUP_LIMIT)); - if (entities != null) { - getLogger().info( - "Vaadin cleanup deleting " + entities.size() - + " expired appengine sessions."); - List<Key> keys = new ArrayList<Key>(); - for (Entity e : entities) { - keys.add(e.getKey()); - } - ds.delete(keys); - } - } - } catch (Exception e) { - getLogger().log(Level.WARNING, "Exception while cleaning.", e); - } - } - - private static final Logger getLogger() { - return Logger.getLogger(GAEApplicationServlet.class.getName()); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/HttpServletRequestListener.java b/src/com/vaadin/terminal/gwt/server/HttpServletRequestListener.java deleted file mode 100644 index d811cadf86..0000000000 --- a/src/com/vaadin/terminal/gwt/server/HttpServletRequestListener.java +++ /dev/null @@ -1,54 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.Serializable; - -import javax.servlet.Filter; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import com.vaadin.Application; -import com.vaadin.service.ApplicationContext.TransactionListener; -import com.vaadin.terminal.Terminal; - -/** - * {@link Application} that implements this interface gets notified of request - * start and end by terminal. - * <p> - * Interface can be used for several helper tasks including: - * <ul> - * <li>Opening and closing database connections - * <li>Implementing {@link ThreadLocal} - * <li>Setting/Getting {@link Cookie} - * </ul> - * <p> - * Alternatives for implementing similar features are are Servlet {@link Filter} - * s and {@link TransactionListener}s in Vaadin. - * - * @since 6.2 - * @see PortletRequestListener - */ -public interface HttpServletRequestListener extends Serializable { - - /** - * This method is called before {@link Terminal} applies the request to - * Application. - * - * @param request - * @param response - */ - public void onRequestStart(HttpServletRequest request, - HttpServletResponse response); - - /** - * This method is called at the end of each request. - * - * @param request - * @param response - */ - public void onRequestEnd(HttpServletRequest request, - HttpServletResponse response); -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/JsonCodec.java b/src/com/vaadin/terminal/gwt/server/JsonCodec.java deleted file mode 100644 index 8199bc6ada..0000000000 --- a/src/com/vaadin/terminal/gwt/server/JsonCodec.java +++ /dev/null @@ -1,792 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.io.Serializable; -import java.lang.reflect.Array; -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.lang.reflect.WildcardType; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import com.vaadin.external.json.JSONArray; -import com.vaadin.external.json.JSONException; -import com.vaadin.external.json.JSONObject; -import com.vaadin.shared.Connector; -import com.vaadin.shared.communication.UidlValue; -import com.vaadin.terminal.gwt.client.communication.JsonEncoder; -import com.vaadin.ui.Component; -import com.vaadin.ui.ConnectorTracker; - -/** - * Decoder for converting RPC parameters and other values from JSON in transfer - * between the client and the server and vice versa. - * - * @since 7.0 - */ -public class JsonCodec implements Serializable { - - private static Map<Class<?>, String> typeToTransportType = new HashMap<Class<?>, String>(); - - /** - * Note! This does not contain primitives. - * <p> - */ - private static Map<String, Class<?>> transportTypeToType = new HashMap<String, Class<?>>(); - - static { - registerType(String.class, JsonEncoder.VTYPE_STRING); - registerType(Connector.class, JsonEncoder.VTYPE_CONNECTOR); - registerType(Boolean.class, JsonEncoder.VTYPE_BOOLEAN); - registerType(boolean.class, JsonEncoder.VTYPE_BOOLEAN); - registerType(Integer.class, JsonEncoder.VTYPE_INTEGER); - registerType(int.class, JsonEncoder.VTYPE_INTEGER); - registerType(Float.class, JsonEncoder.VTYPE_FLOAT); - registerType(float.class, JsonEncoder.VTYPE_FLOAT); - registerType(Double.class, JsonEncoder.VTYPE_DOUBLE); - registerType(double.class, JsonEncoder.VTYPE_DOUBLE); - registerType(Long.class, JsonEncoder.VTYPE_LONG); - registerType(long.class, JsonEncoder.VTYPE_LONG); - registerType(String[].class, JsonEncoder.VTYPE_STRINGARRAY); - registerType(Object[].class, JsonEncoder.VTYPE_ARRAY); - registerType(Map.class, JsonEncoder.VTYPE_MAP); - registerType(HashMap.class, JsonEncoder.VTYPE_MAP); - registerType(List.class, JsonEncoder.VTYPE_LIST); - registerType(Set.class, JsonEncoder.VTYPE_SET); - } - - private static void registerType(Class<?> type, String transportType) { - typeToTransportType.put(type, transportType); - if (!type.isPrimitive()) { - transportTypeToType.put(transportType, type); - } - } - - public static boolean isInternalTransportType(String transportType) { - return transportTypeToType.containsKey(transportType); - } - - public static boolean isInternalType(Type type) { - if (type instanceof Class && ((Class<?>) type).isPrimitive()) { - if (type == byte.class || type == char.class) { - // Almost all primitive types are handled internally - return false; - } - // All primitive types are handled internally - return true; - } else if (type == UidlValue.class) { - // UidlValue is a special internal type wrapping type info and a - // value - return true; - } - return typeToTransportType.containsKey(getClassForType(type)); - } - - private static Class<?> getClassForType(Type type) { - if (type instanceof ParameterizedType) { - return (Class<?>) (((ParameterizedType) type).getRawType()); - } else if (type instanceof Class<?>) { - return (Class<?>) type; - } else { - return null; - } - } - - private static Class<?> getType(String transportType) { - return transportTypeToType.get(transportType); - } - - public static Object decodeInternalOrCustomType(Type targetType, - Object value, ConnectorTracker connectorTracker) - throws JSONException { - if (isInternalType(targetType)) { - return decodeInternalType(targetType, false, value, - connectorTracker); - } else { - return decodeCustomType(targetType, value, connectorTracker); - } - } - - public static Object decodeCustomType(Type targetType, Object value, - ConnectorTracker connectorTracker) throws JSONException { - if (isInternalType(targetType)) { - throw new JSONException("decodeCustomType cannot be used for " - + targetType + ", which is an internal type"); - } - - // Try to decode object using fields - if (value == JSONObject.NULL) { - return null; - } else if (targetType == byte.class || targetType == Byte.class) { - return Byte.valueOf(String.valueOf(value)); - } else if (targetType == char.class || targetType == Character.class) { - return Character.valueOf(String.valueOf(value).charAt(0)); - } else if (targetType instanceof Class<?> - && ((Class<?>) targetType).isArray()) { - // Legacy Object[] and String[] handled elsewhere, this takes care - // of generic arrays - Class<?> componentType = ((Class<?>) targetType).getComponentType(); - return decodeArray(componentType, (JSONArray) value, - connectorTracker); - } else if (targetType instanceof GenericArrayType) { - Type componentType = ((GenericArrayType) targetType) - .getGenericComponentType(); - return decodeArray(componentType, (JSONArray) value, - connectorTracker); - } else if (targetType == JSONObject.class - || targetType == JSONArray.class) { - return value; - } else { - return decodeObject(targetType, (JSONObject) value, - connectorTracker); - } - } - - private static Object decodeArray(Type componentType, JSONArray value, - ConnectorTracker connectorTracker) throws JSONException { - Class<?> componentClass = getClassForType(componentType); - Object array = Array.newInstance(componentClass, value.length()); - for (int i = 0; i < value.length(); i++) { - Object decodedValue = decodeInternalOrCustomType(componentType, - value.get(i), connectorTracker); - Array.set(array, i, decodedValue); - } - return array; - } - - /** - * Decodes a value that is of an internal type. - * <p> - * Ensures the encoded value is of the same type as target type. - * </p> - * <p> - * Allows restricting collections so that they must be declared using - * generics. If this is used then all objects in the collection are encoded - * using the declared type. Otherwise only internal types are allowed in - * collections. - * </p> - * - * @param targetType - * The type that should be returned by this method - * @param valueAndType - * The encoded value and type array - * @param application - * A reference to the application - * @param enforceGenericsInCollections - * true if generics should be enforce, false to only allow - * internal types in collections - * @return - * @throws JSONException - */ - public static Object decodeInternalType(Type targetType, - boolean restrictToInternalTypes, Object encodedJsonValue, - ConnectorTracker connectorTracker) throws JSONException { - if (!isInternalType(targetType)) { - throw new JSONException("Type " + targetType - + " is not a supported internal type."); - } - String transportType = getInternalTransportType(targetType); - - if (encodedJsonValue == JSONObject.NULL) { - return null; - } - - // UidlValue - if (targetType == UidlValue.class) { - return decodeUidlValue((JSONArray) encodedJsonValue, - connectorTracker); - } - - // Collections - if (JsonEncoder.VTYPE_LIST.equals(transportType)) { - return decodeList(targetType, restrictToInternalTypes, - (JSONArray) encodedJsonValue, connectorTracker); - } else if (JsonEncoder.VTYPE_SET.equals(transportType)) { - return decodeSet(targetType, restrictToInternalTypes, - (JSONArray) encodedJsonValue, connectorTracker); - } else if (JsonEncoder.VTYPE_MAP.equals(transportType)) { - return decodeMap(targetType, restrictToInternalTypes, - encodedJsonValue, connectorTracker); - } - - // Arrays - if (JsonEncoder.VTYPE_ARRAY.equals(transportType)) { - - return decodeObjectArray(targetType, (JSONArray) encodedJsonValue, - connectorTracker); - - } else if (JsonEncoder.VTYPE_STRINGARRAY.equals(transportType)) { - return decodeStringArray((JSONArray) encodedJsonValue); - } - - // Special Vaadin types - - String stringValue = String.valueOf(encodedJsonValue); - - if (JsonEncoder.VTYPE_CONNECTOR.equals(transportType)) { - return connectorTracker.getConnector(stringValue); - } - - // Legacy types - - if (JsonEncoder.VTYPE_STRING.equals(transportType)) { - return stringValue; - } else if (JsonEncoder.VTYPE_INTEGER.equals(transportType)) { - return Integer.valueOf(stringValue); - } else if (JsonEncoder.VTYPE_LONG.equals(transportType)) { - return Long.valueOf(stringValue); - } else if (JsonEncoder.VTYPE_FLOAT.equals(transportType)) { - return Float.valueOf(stringValue); - } else if (JsonEncoder.VTYPE_DOUBLE.equals(transportType)) { - return Double.valueOf(stringValue); - } else if (JsonEncoder.VTYPE_BOOLEAN.equals(transportType)) { - return Boolean.valueOf(stringValue); - } - - throw new JSONException("Unknown type " + transportType); - } - - private static UidlValue decodeUidlValue(JSONArray encodedJsonValue, - ConnectorTracker connectorTracker) throws JSONException { - String type = encodedJsonValue.getString(0); - - Object decodedValue = decodeInternalType(getType(type), true, - encodedJsonValue.get(1), connectorTracker); - return new UidlValue(decodedValue); - } - - private static boolean transportTypesCompatible( - String encodedTransportType, String transportType) { - if (encodedTransportType == null) { - return false; - } - if (encodedTransportType.equals(transportType)) { - return true; - } - if (encodedTransportType.equals(JsonEncoder.VTYPE_NULL)) { - return true; - } - - return false; - } - - private static Map<Object, Object> decodeMap(Type targetType, - boolean restrictToInternalTypes, Object jsonMap, - ConnectorTracker connectorTracker) throws JSONException { - if (jsonMap instanceof JSONArray) { - // Client-side has no declared type information to determine - // encoding method for empty maps, so these are handled separately. - // See #8906. - JSONArray jsonArray = (JSONArray) jsonMap; - if (jsonArray.length() == 0) { - return new HashMap<Object, Object>(); - } - } - - if (!restrictToInternalTypes && targetType instanceof ParameterizedType) { - Type keyType = ((ParameterizedType) targetType) - .getActualTypeArguments()[0]; - Type valueType = ((ParameterizedType) targetType) - .getActualTypeArguments()[1]; - if (keyType == String.class) { - return decodeStringMap(valueType, (JSONObject) jsonMap, - connectorTracker); - } else if (keyType == Connector.class) { - return decodeConnectorMap(valueType, (JSONObject) jsonMap, - connectorTracker); - } else { - return decodeObjectMap(keyType, valueType, (JSONArray) jsonMap, - connectorTracker); - } - } else { - return decodeStringMap(UidlValue.class, (JSONObject) jsonMap, - connectorTracker); - } - } - - private static Map<Object, Object> decodeObjectMap(Type keyType, - Type valueType, JSONArray jsonMap, ConnectorTracker connectorTracker) - throws JSONException { - Map<Object, Object> map = new HashMap<Object, Object>(); - - JSONArray keys = jsonMap.getJSONArray(0); - JSONArray values = jsonMap.getJSONArray(1); - - assert (keys.length() == values.length()); - - for (int i = 0; i < keys.length(); i++) { - Object key = decodeInternalOrCustomType(keyType, keys.get(i), - connectorTracker); - Object value = decodeInternalOrCustomType(valueType, values.get(i), - connectorTracker); - - map.put(key, value); - } - - return map; - } - - private static Map<Object, Object> decodeConnectorMap(Type valueType, - JSONObject jsonMap, ConnectorTracker connectorTracker) - throws JSONException { - Map<Object, Object> map = new HashMap<Object, Object>(); - - for (Iterator<?> iter = jsonMap.keys(); iter.hasNext();) { - String key = (String) iter.next(); - Object value = decodeInternalOrCustomType(valueType, - jsonMap.get(key), connectorTracker); - if (valueType == UidlValue.class) { - value = ((UidlValue) value).getValue(); - } - map.put(connectorTracker.getConnector(key), value); - } - - return map; - } - - private static Map<Object, Object> decodeStringMap(Type valueType, - JSONObject jsonMap, ConnectorTracker connectorTracker) - throws JSONException { - Map<Object, Object> map = new HashMap<Object, Object>(); - - for (Iterator<?> iter = jsonMap.keys(); iter.hasNext();) { - String key = (String) iter.next(); - Object value = decodeInternalOrCustomType(valueType, - jsonMap.get(key), connectorTracker); - if (valueType == UidlValue.class) { - value = ((UidlValue) value).getValue(); - } - map.put(key, value); - } - - return map; - } - - /** - * @param targetType - * @param restrictToInternalTypes - * @param typeIndex - * The index of a generic type to use to define the child type - * that should be decoded - * @param encodedValueAndType - * @param application - * @return - * @throws JSONException - */ - private static Object decodeParametrizedType(Type targetType, - boolean restrictToInternalTypes, int typeIndex, Object value, - ConnectorTracker connectorTracker) throws JSONException { - if (!restrictToInternalTypes && targetType instanceof ParameterizedType) { - Type childType = ((ParameterizedType) targetType) - .getActualTypeArguments()[typeIndex]; - // Only decode the given type - return decodeInternalOrCustomType(childType, value, - connectorTracker); - } else { - // Only UidlValue when not enforcing a given type to avoid security - // issues - UidlValue decodeInternalType = (UidlValue) decodeInternalType( - UidlValue.class, true, value, connectorTracker); - return decodeInternalType.getValue(); - } - } - - private static Object decodeEnum(Class<? extends Enum> cls, JSONObject value) { - String enumIdentifier = String.valueOf(value); - return Enum.valueOf(cls, enumIdentifier); - } - - private static String[] decodeStringArray(JSONArray jsonArray) - throws JSONException { - int length = jsonArray.length(); - List<String> tokens = new ArrayList<String>(length); - for (int i = 0; i < length; ++i) { - tokens.add(jsonArray.getString(i)); - } - return tokens.toArray(new String[tokens.size()]); - } - - private static Object[] decodeObjectArray(Type targetType, - JSONArray jsonArray, ConnectorTracker connectorTracker) - throws JSONException { - List list = decodeList(List.class, true, jsonArray, connectorTracker); - return list.toArray(new Object[list.size()]); - } - - private static List<Object> decodeList(Type targetType, - boolean restrictToInternalTypes, JSONArray jsonArray, - ConnectorTracker connectorTracker) throws JSONException { - List<Object> list = new ArrayList<Object>(); - for (int i = 0; i < jsonArray.length(); ++i) { - // each entry always has two elements: type and value - Object encodedValue = jsonArray.get(i); - Object decodedChild = decodeParametrizedType(targetType, - restrictToInternalTypes, 0, encodedValue, connectorTracker); - list.add(decodedChild); - } - return list; - } - - private static Set<Object> decodeSet(Type targetType, - boolean restrictToInternalTypes, JSONArray jsonArray, - ConnectorTracker connectorTracker) throws JSONException { - HashSet<Object> set = new HashSet<Object>(); - set.addAll(decodeList(targetType, restrictToInternalTypes, jsonArray, - connectorTracker)); - return set; - } - - /** - * Returns the name that should be used as field name in the JSON. We strip - * "set" from the setter, keeping the result - this is easy to do on both - * server and client, avoiding some issues with cASE. E.g setZIndex() - * becomes "zIndex". Also ensures that both getter and setter are present, - * returning null otherwise. - * - * @param pd - * @return the name to be used or null if both getter and setter are not - * found. - */ - static String getTransportFieldName(PropertyDescriptor pd) { - if (pd.getReadMethod() == null || pd.getWriteMethod() == null) { - return null; - } - String fieldName = pd.getWriteMethod().getName().substring(3); - fieldName = Character.toLowerCase(fieldName.charAt(0)) - + fieldName.substring(1); - return fieldName; - } - - private static Object decodeObject(Type targetType, - JSONObject serializedObject, ConnectorTracker connectorTracker) - throws JSONException { - - Class<?> targetClass = getClassForType(targetType); - if (Enum.class.isAssignableFrom(targetClass)) { - return decodeEnum(targetClass.asSubclass(Enum.class), - serializedObject); - } - - try { - Object decodedObject = targetClass.newInstance(); - for (PropertyDescriptor pd : Introspector.getBeanInfo(targetClass) - .getPropertyDescriptors()) { - - String fieldName = getTransportFieldName(pd); - if (fieldName == null) { - continue; - } - Object encodedFieldValue = serializedObject.get(fieldName); - Type fieldType = pd.getReadMethod().getGenericReturnType(); - Object decodedFieldValue = decodeInternalOrCustomType( - fieldType, encodedFieldValue, connectorTracker); - - pd.getWriteMethod().invoke(decodedObject, decodedFieldValue); - } - - return decodedObject; - } catch (IllegalArgumentException e) { - throw new JSONException(e); - } catch (IllegalAccessException e) { - throw new JSONException(e); - } catch (InvocationTargetException e) { - throw new JSONException(e); - } catch (InstantiationException e) { - throw new JSONException(e); - } catch (IntrospectionException e) { - throw new JSONException(e); - } - } - - public static Object encode(Object value, Object referenceValue, - Type valueType, ConnectorTracker connectorTracker) - throws JSONException { - - if (valueType == null) { - throw new IllegalArgumentException("type must be defined"); - } - - if (valueType instanceof WildcardType) { - throw new IllegalStateException( - "Can not serialize type with wildcard: " + valueType); - } - - if (null == value) { - return encodeNull(); - } - - if (value instanceof String[]) { - String[] array = (String[]) value; - JSONArray jsonArray = new JSONArray(); - for (int i = 0; i < array.length; ++i) { - jsonArray.put(array[i]); - } - return jsonArray; - } else if (value instanceof String) { - return value; - } else if (value instanceof Boolean) { - return value; - } else if (value instanceof Number) { - return value; - } else if (value instanceof Character) { - // Character is not a Number - return value; - } else if (value instanceof Collection) { - Collection<?> collection = (Collection<?>) value; - JSONArray jsonArray = encodeCollection(valueType, collection, - connectorTracker); - return jsonArray; - } else if (valueType instanceof Class<?> - && ((Class<?>) valueType).isArray()) { - JSONArray jsonArray = encodeArrayContents( - ((Class<?>) valueType).getComponentType(), value, - connectorTracker); - return jsonArray; - } else if (valueType instanceof GenericArrayType) { - Type componentType = ((GenericArrayType) valueType) - .getGenericComponentType(); - JSONArray jsonArray = encodeArrayContents(componentType, value, - connectorTracker); - return jsonArray; - } else if (value instanceof Map) { - Object jsonMap = encodeMap(valueType, (Map<?, ?>) value, - connectorTracker); - return jsonMap; - } else if (value instanceof Connector) { - Connector connector = (Connector) value; - if (value instanceof Component - && !(AbstractCommunicationManager - .isVisible((Component) value))) { - return encodeNull(); - } - return connector.getConnectorId(); - } else if (value instanceof Enum) { - return encodeEnum((Enum<?>) value, connectorTracker); - } else if (value instanceof JSONArray || value instanceof JSONObject) { - return value; - } else { - // Any object that we do not know how to encode we encode by looping - // through fields - return encodeObject(value, referenceValue, connectorTracker); - } - } - - private static Object encodeNull() { - return JSONObject.NULL; - } - - private static Object encodeObject(Object value, Object referenceValue, - ConnectorTracker connectorTracker) throws JSONException { - JSONObject jsonMap = new JSONObject(); - - try { - for (PropertyDescriptor pd : Introspector.getBeanInfo( - value.getClass()).getPropertyDescriptors()) { - String fieldName = getTransportFieldName(pd); - if (fieldName == null) { - continue; - } - Method getterMethod = pd.getReadMethod(); - // We can't use PropertyDescriptor.getPropertyType() as it does - // not support generics - Type fieldType = getterMethod.getGenericReturnType(); - Object fieldValue = getterMethod.invoke(value, (Object[]) null); - boolean equals = false; - Object referenceFieldValue = null; - if (referenceValue != null) { - referenceFieldValue = getterMethod.invoke(referenceValue, - (Object[]) null); - equals = equals(fieldValue, referenceFieldValue); - } - if (!equals) { - if (jsonMap.has(fieldName)) { - throw new RuntimeException( - "Can't encode " - + value.getClass().getName() - + " as it has multiple fields with the name " - + fieldName.toLowerCase() - + ". This can happen if only casing distinguishes one property name from another."); - } - jsonMap.put( - fieldName, - encode(fieldValue, referenceFieldValue, fieldType, - connectorTracker)); - // } else { - // System.out.println("Skipping field " + fieldName - // + " of type " + fieldType.getName() - // + " for object " + value.getClass().getName() - // + " as " + fieldValue + "==" + referenceFieldValue); - } - } - } catch (Exception e) { - // TODO: Should exceptions be handled in a different way? - throw new JSONException(e); - } - return jsonMap; - } - - /** - * Compares the value with the reference. If they match, returns true. - * - * @param fieldValue - * @param referenceValue - * @return - */ - private static boolean equals(Object fieldValue, Object referenceValue) { - if (fieldValue == null) { - return referenceValue == null; - } - - if (fieldValue.equals(referenceValue)) { - return true; - } - - return false; - } - - private static String encodeEnum(Enum<?> e, - ConnectorTracker connectorTracker) throws JSONException { - return e.name(); - } - - private static JSONArray encodeArrayContents(Type componentType, - Object array, ConnectorTracker connectorTracker) - throws JSONException { - JSONArray jsonArray = new JSONArray(); - for (int i = 0; i < Array.getLength(array); i++) { - jsonArray.put(encode(Array.get(array, i), null, componentType, - connectorTracker)); - } - return jsonArray; - } - - private static JSONArray encodeCollection(Type targetType, - Collection collection, ConnectorTracker connectorTracker) - throws JSONException { - JSONArray jsonArray = new JSONArray(); - for (Object o : collection) { - jsonArray.put(encodeChild(targetType, 0, o, connectorTracker)); - } - return jsonArray; - } - - private static Object encodeChild(Type targetType, int typeIndex, Object o, - ConnectorTracker connectorTracker) throws JSONException { - if (targetType instanceof ParameterizedType) { - Type childType = ((ParameterizedType) targetType) - .getActualTypeArguments()[typeIndex]; - // Encode using the given type - return encode(o, null, childType, connectorTracker); - } else { - throw new JSONException("Collection is missing generics"); - } - } - - private static Object encodeMap(Type mapType, Map<?, ?> map, - ConnectorTracker connectorTracker) throws JSONException { - Type keyType, valueType; - - if (mapType instanceof ParameterizedType) { - keyType = ((ParameterizedType) mapType).getActualTypeArguments()[0]; - valueType = ((ParameterizedType) mapType).getActualTypeArguments()[1]; - } else { - throw new JSONException("Map is missing generics"); - } - - if (map.isEmpty()) { - // Client -> server encodes empty map as an empty array because of - // #8906. Do the same for server -> client to maintain symmetry. - return new JSONArray(); - } - - if (keyType == String.class) { - return encodeStringMap(valueType, map, connectorTracker); - } else if (keyType == Connector.class) { - return encodeConnectorMap(valueType, map, connectorTracker); - } else { - return encodeObjectMap(keyType, valueType, map, connectorTracker); - } - } - - private static JSONArray encodeObjectMap(Type keyType, Type valueType, - Map<?, ?> map, ConnectorTracker connectorTracker) - throws JSONException { - JSONArray keys = new JSONArray(); - JSONArray values = new JSONArray(); - - for (Entry<?, ?> entry : map.entrySet()) { - Object encodedKey = encode(entry.getKey(), null, keyType, - connectorTracker); - Object encodedValue = encode(entry.getValue(), null, valueType, - connectorTracker); - - keys.put(encodedKey); - values.put(encodedValue); - } - - return new JSONArray(Arrays.asList(keys, values)); - } - - private static JSONObject encodeConnectorMap(Type valueType, Map<?, ?> map, - ConnectorTracker connectorTracker) throws JSONException { - JSONObject jsonMap = new JSONObject(); - - for (Entry<?, ?> entry : map.entrySet()) { - Connector key = (Connector) entry.getKey(); - Object encodedValue = encode(entry.getValue(), null, valueType, - connectorTracker); - jsonMap.put(key.getConnectorId(), encodedValue); - } - - return jsonMap; - } - - private static JSONObject encodeStringMap(Type valueType, Map<?, ?> map, - ConnectorTracker connectorTracker) throws JSONException { - JSONObject jsonMap = new JSONObject(); - - for (Entry<?, ?> entry : map.entrySet()) { - String key = (String) entry.getKey(); - Object encodedValue = encode(entry.getValue(), null, valueType, - connectorTracker); - jsonMap.put(key, encodedValue); - } - - return jsonMap; - } - - /** - * Gets the transport type for the given class. Returns null if no transport - * type can be found. - * - * @param valueType - * The type that should be transported - * @return - * @throws JSONException - */ - private static String getInternalTransportType(Type valueType) { - return typeToTransportType.get(getClassForType(valueType)); - } - - private static String getCustomTransportType(Class<?> targetType) { - return targetType.getName(); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java b/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java deleted file mode 100644 index 5a830ddb63..0000000000 --- a/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java +++ /dev/null @@ -1,1022 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.PrintWriter; -import java.io.Serializable; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.Stack; -import java.util.Vector; -import java.util.logging.Logger; - -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.StreamVariable; -import com.vaadin.terminal.VariableOwner; -import com.vaadin.ui.Alignment; -import com.vaadin.ui.Component; -import com.vaadin.ui.CustomLayout; - -/** - * User Interface Description Language Target. - * - * TODO document better: role of this class, UIDL format, attributes, variables, - * etc. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.0 - */ -@SuppressWarnings("serial") -public class JsonPaintTarget implements PaintTarget { - - /* Document type declarations */ - - private final static String UIDL_ARG_NAME = "name"; - - private final Stack<String> mOpenTags; - - private final Stack<JsonTag> openJsonTags; - - // these match each other element-wise - private final Stack<ClientConnector> openPaintables; - private final Stack<String> openPaintableTags; - - private final PrintWriter uidlBuffer; - - private boolean closed = false; - - private final AbstractCommunicationManager manager; - - private int changes = 0; - - private final Set<Object> usedResources = new HashSet<Object>(); - - private boolean customLayoutArgumentsOpen = false; - - private JsonTag tag; - - private boolean cacheEnabled = false; - - private final Set<Class<? extends ClientConnector>> usedClientConnectors = new HashSet<Class<? extends ClientConnector>>(); - - /** - * Creates a new JsonPaintTarget. - * - * @param manager - * @param outWriter - * A character-output stream. - * @param cachingRequired - * true if this is not a full repaint, i.e. caches are to be - * used. - * @throws PaintException - * if the paint operation failed. - */ - public JsonPaintTarget(AbstractCommunicationManager manager, - PrintWriter outWriter, boolean cachingRequired) - throws PaintException { - - this.manager = manager; - - // Sets the target for UIDL writing - uidlBuffer = outWriter; - - // Initialize tag-writing - mOpenTags = new Stack<String>(); - openJsonTags = new Stack<JsonTag>(); - - openPaintables = new Stack<ClientConnector>(); - openPaintableTags = new Stack<String>(); - - cacheEnabled = cachingRequired; - } - - @Override - public void startTag(String tagName) throws PaintException { - startTag(tagName, false); - } - - /** - * Prints the element start tag. - * - * <pre> - * Todo: - * Checking of input values - * - * </pre> - * - * @param tagName - * the name of the start tag. - * @throws PaintException - * if the paint operation failed. - * - */ - public void startTag(String tagName, boolean isChildNode) - throws PaintException { - // In case of null data output nothing: - if (tagName == null) { - throw new NullPointerException(); - } - - // Ensures that the target is open - if (closed) { - throw new PaintException( - "Attempted to write to a closed PaintTarget."); - } - - if (tag != null) { - openJsonTags.push(tag); - } - // Checks tagName and attributes here - mOpenTags.push(tagName); - - tag = new JsonTag(tagName); - - customLayoutArgumentsOpen = false; - - } - - /** - * Prints the element end tag. - * - * If the parent tag is closed before every child tag is closed an - * PaintException is raised. - * - * @param tag - * the name of the end tag. - * @throws Paintexception - * if the paint operation failed. - */ - - @Override - public void endTag(String tagName) throws PaintException { - // In case of null data output nothing: - if (tagName == null) { - throw new NullPointerException(); - } - - // Ensure that the target is open - if (closed) { - throw new PaintException( - "Attempted to write to a closed PaintTarget."); - } - - if (openJsonTags.size() > 0) { - final JsonTag parent = openJsonTags.pop(); - - String lastTag = ""; - - lastTag = mOpenTags.pop(); - if (!tagName.equalsIgnoreCase(lastTag)) { - throw new PaintException("Invalid UIDL: wrong ending tag: '" - + tagName + "' expected: '" + lastTag + "'."); - } - - parent.addData(tag.getJSON()); - - tag = parent; - } else { - changes++; - uidlBuffer.print(((changes > 1) ? "," : "") + tag.getJSON()); - tag = null; - } - } - - /** - * Substitutes the XML sensitive characters with predefined XML entities. - * - * @param xml - * the String to be substituted. - * @return A new string instance where all occurrences of XML sensitive - * characters are substituted with entities. - */ - static public String escapeXML(String xml) { - if (xml == null || xml.length() <= 0) { - return ""; - } - return escapeXML(new StringBuilder(xml)).toString(); - } - - /** - * Substitutes the XML sensitive characters with predefined XML entities. - * - * @param xml - * the String to be substituted. - * @return A new StringBuilder instance where all occurrences of XML - * sensitive characters are substituted with entities. - * - */ - static StringBuilder escapeXML(StringBuilder xml) { - if (xml == null || xml.length() <= 0) { - return new StringBuilder(""); - } - - final StringBuilder result = new StringBuilder(xml.length() * 2); - - for (int i = 0; i < xml.length(); i++) { - final char c = xml.charAt(i); - final String s = toXmlChar(c); - if (s != null) { - result.append(s); - } else { - result.append(c); - } - } - return result; - } - - /** - * Escapes the given string so it can safely be used as a JSON string. - * - * @param s - * The string to escape - * @return Escaped version of the string - */ - static public String escapeJSON(String s) { - // FIXME: Move this method to another class as other classes use it - // also. - if (s == null) { - return ""; - } - final StringBuilder sb = new StringBuilder(); - for (int i = 0; i < s.length(); i++) { - final char ch = s.charAt(i); - switch (ch) { - case '"': - sb.append("\\\""); - break; - case '\\': - sb.append("\\\\"); - break; - case '\b': - sb.append("\\b"); - break; - case '\f': - sb.append("\\f"); - break; - case '\n': - sb.append("\\n"); - break; - case '\r': - sb.append("\\r"); - break; - case '\t': - sb.append("\\t"); - break; - case '/': - sb.append("\\/"); - break; - default: - if (ch >= '\u0000' && ch <= '\u001F') { - final String ss = Integer.toHexString(ch); - sb.append("\\u"); - for (int k = 0; k < 4 - ss.length(); k++) { - sb.append('0'); - } - sb.append(ss.toUpperCase()); - } else { - sb.append(ch); - } - } - } - return sb.toString(); - } - - /** - * Substitutes a XML sensitive character with predefined XML entity. - * - * @param c - * the Character to be replaced with an entity. - * @return String of the entity or null if character is not to be replaced - * with an entity. - */ - private static String toXmlChar(char c) { - switch (c) { - case '&': - return "&"; // & => & - case '>': - return ">"; // > => > - case '<': - return "<"; // < => < - case '"': - return """; // " => " - case '\'': - return "'"; // ' => ' - default: - return null; - } - } - - /** - * Prints XML-escaped text. - * - * @param str - * @throws PaintException - * if the paint operation failed. - * - */ - - @Override - public void addText(String str) throws PaintException { - tag.addData("\"" + escapeJSON(str) + "\""); - } - - @Override - public void addAttribute(String name, boolean value) throws PaintException { - tag.addAttribute("\"" + name + "\":" + (value ? "true" : "false")); - } - - @Override - public void addAttribute(String name, Resource value) throws PaintException { - if (value == null) { - throw new NullPointerException(); - } - ResourceReference reference = ResourceReference.create(value); - addAttribute(name, reference.getURL()); - } - - @Override - public void addAttribute(String name, int value) throws PaintException { - tag.addAttribute("\"" + name + "\":" + String.valueOf(value)); - } - - @Override - public void addAttribute(String name, long value) throws PaintException { - tag.addAttribute("\"" + name + "\":" + String.valueOf(value)); - } - - @Override - public void addAttribute(String name, float value) throws PaintException { - tag.addAttribute("\"" + name + "\":" + String.valueOf(value)); - } - - @Override - public void addAttribute(String name, double value) throws PaintException { - tag.addAttribute("\"" + name + "\":" + String.valueOf(value)); - } - - @Override - public void addAttribute(String name, String value) throws PaintException { - // In case of null data output nothing: - if ((value == null) || (name == null)) { - throw new NullPointerException( - "Parameters must be non-null strings"); - } - - tag.addAttribute("\"" + name + "\":\"" + escapeJSON(value) + "\""); - - if (customLayoutArgumentsOpen && "template".equals(name)) { - getUsedResources().add("layouts/" + value + ".html"); - } - - if (name.equals("locale")) { - manager.requireLocale(value); - } - - } - - @Override - public void addAttribute(String name, Component value) - throws PaintException { - final String id = value.getConnectorId(); - addAttribute(name, id); - } - - @Override - public void addAttribute(String name, Map<?, ?> value) - throws PaintException { - - StringBuilder sb = new StringBuilder(); - sb.append("\""); - sb.append(name); - sb.append("\":"); - sb.append("{"); - for (Iterator<?> it = value.keySet().iterator(); it.hasNext();) { - Object key = it.next(); - Object mapValue = value.get(key); - sb.append("\""); - if (key instanceof ClientConnector) { - sb.append(((ClientConnector) key).getConnectorId()); - } else { - sb.append(escapeJSON(key.toString())); - } - sb.append("\":"); - if (mapValue instanceof Float || mapValue instanceof Integer - || mapValue instanceof Double - || mapValue instanceof Boolean - || mapValue instanceof Alignment) { - sb.append(mapValue); - } else { - sb.append("\""); - sb.append(escapeJSON(mapValue.toString())); - sb.append("\""); - } - if (it.hasNext()) { - sb.append(","); - } - } - sb.append("}"); - - tag.addAttribute(sb.toString()); - } - - @Override - public void addAttribute(String name, Object[] values) { - // In case of null data output nothing: - if ((values == null) || (name == null)) { - throw new NullPointerException( - "Parameters must be non-null strings"); - } - final StringBuilder buf = new StringBuilder(); - buf.append("\"" + name + "\":["); - for (int i = 0; i < values.length; i++) { - if (i > 0) { - buf.append(","); - } - buf.append("\""); - buf.append(escapeJSON(values[i].toString())); - buf.append("\""); - } - buf.append("]"); - tag.addAttribute(buf.toString()); - } - - @Override - public void addVariable(VariableOwner owner, String name, String value) - throws PaintException { - tag.addVariable(new StringVariable(owner, name, escapeJSON(value))); - } - - @Override - public void addVariable(VariableOwner owner, String name, Component value) - throws PaintException { - tag.addVariable(new StringVariable(owner, name, value.getConnectorId())); - } - - @Override - public void addVariable(VariableOwner owner, String name, int value) - throws PaintException { - tag.addVariable(new IntVariable(owner, name, value)); - } - - @Override - public void addVariable(VariableOwner owner, String name, long value) - throws PaintException { - tag.addVariable(new LongVariable(owner, name, value)); - } - - @Override - public void addVariable(VariableOwner owner, String name, float value) - throws PaintException { - tag.addVariable(new FloatVariable(owner, name, value)); - } - - @Override - public void addVariable(VariableOwner owner, String name, double value) - throws PaintException { - tag.addVariable(new DoubleVariable(owner, name, value)); - } - - @Override - public void addVariable(VariableOwner owner, String name, boolean value) - throws PaintException { - tag.addVariable(new BooleanVariable(owner, name, value)); - } - - @Override - public void addVariable(VariableOwner owner, String name, String[] value) - throws PaintException { - tag.addVariable(new ArrayVariable(owner, name, value)); - } - - /** - * Adds a upload stream type variable. - * - * TODO not converted for JSON - * - * @param owner - * the Listener for variable changes. - * @param name - * the Variable name. - * - * @throws PaintException - * if the paint operation failed. - */ - - @Override - public void addUploadStreamVariable(VariableOwner owner, String name) - throws PaintException { - startTag("uploadstream"); - addAttribute(UIDL_ARG_NAME, name); - endTag("uploadstream"); - } - - /** - * Prints the single text section. - * - * Prints full text section. The section data is escaped - * - * @param sectionTagName - * the name of the tag. - * @param sectionData - * the section data to be printed. - * @throws PaintException - * if the paint operation failed. - */ - - @Override - public void addSection(String sectionTagName, String sectionData) - throws PaintException { - tag.addData("{\"" + sectionTagName + "\":\"" + escapeJSON(sectionData) - + "\"}"); - } - - /** - * Adds XML directly to UIDL. - * - * @param xml - * the Xml to be added. - * @throws PaintException - * if the paint operation failed. - */ - - @Override - public void addUIDL(String xml) throws PaintException { - - // Ensure that the target is open - if (closed) { - throw new PaintException( - "Attempted to write to a closed PaintTarget."); - } - - // Make sure that the open start tag is closed before - // anything is written. - - // Escape and write what was given - if (xml != null) { - tag.addData("\"" + escapeJSON(xml) + "\""); - } - - } - - /** - * Adds XML section with namespace. - * - * @param sectionTagName - * the name of the tag. - * @param sectionData - * the section data. - * @param namespace - * the namespace to be added. - * @throws PaintException - * if the paint operation failed. - * - * @see com.vaadin.terminal.PaintTarget#addXMLSection(String, String, - * String) - */ - - @Override - public void addXMLSection(String sectionTagName, String sectionData, - String namespace) throws PaintException { - - // Ensure that the target is open - if (closed) { - throw new PaintException( - "Attempted to write to a closed PaintTarget."); - } - - startTag(sectionTagName); - if (namespace != null) { - addAttribute("xmlns", namespace); - } - - if (sectionData != null) { - tag.addData("\"" + escapeJSON(sectionData) + "\""); - } - endTag(sectionTagName); - } - - /** - * Gets the UIDL already printed to stream. Paint target must be closed - * before the <code>getUIDL</code> can be called. - * - * @return the UIDL. - */ - public String getUIDL() { - if (closed) { - return uidlBuffer.toString(); - } - throw new IllegalStateException( - "Tried to read UIDL from open PaintTarget"); - } - - /** - * Closes the paint target. Paint target must be closed before the - * <code>getUIDL</code> can be called. Subsequent attempts to write to paint - * target. If the target was already closed, call to this function is - * ignored. will generate an exception. - * - * @throws PaintException - * if the paint operation failed. - */ - public void close() throws PaintException { - if (tag != null) { - uidlBuffer.write(tag.getJSON()); - } - flush(); - closed = true; - } - - /** - * Method flush. - */ - private void flush() { - uidlBuffer.flush(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.PaintTarget#startPaintable(com.vaadin.terminal - * .Paintable, java.lang.String) - */ - - @Override - public PaintStatus startPaintable(Component connector, String tagName) - throws PaintException { - boolean topLevelPaintable = openPaintables.isEmpty(); - - getLogger().fine( - "startPaintable for " + connector.getClass().getName() + "@" - + Integer.toHexString(connector.hashCode())); - startTag(tagName, true); - - openPaintables.push(connector); - openPaintableTags.push(tagName); - - addAttribute("id", connector.getConnectorId()); - - // Only paint top level paintables. All sub paintables are marked as - // queued and painted separately later. - if (!topLevelPaintable) { - return PaintStatus.CACHED; - } - - if (connector instanceof CustomLayout) { - customLayoutArgumentsOpen = true; - } - return PaintStatus.PAINTING; - } - - @Override - public void endPaintable(Component paintable) throws PaintException { - getLogger().fine( - "endPaintable for " + paintable.getClass().getName() + "@" - + Integer.toHexString(paintable.hashCode())); - - ClientConnector openPaintable = openPaintables.peek(); - if (paintable != openPaintable) { - throw new PaintException("Invalid UIDL: closing wrong paintable: '" - + paintable.getConnectorId() + "' expected: '" - + openPaintable.getConnectorId() + "'."); - } - // remove paintable from the stack - openPaintables.pop(); - String openTag = openPaintableTags.pop(); - endTag(openTag); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.PaintTarget#addCharacterData(java.lang.String ) - */ - - @Override - public void addCharacterData(String text) throws PaintException { - if (text != null) { - tag.addData(text); - } - } - - /** - * This is basically a container for UI components variables, that will be - * added at the end of JSON object. - * - * @author mattitahvonen - * - */ - class JsonTag implements Serializable { - boolean firstField = false; - - Vector<Object> variables = new Vector<Object>(); - - Vector<Object> children = new Vector<Object>(); - - Vector<Object> attr = new Vector<Object>(); - - StringBuilder data = new StringBuilder(); - - public boolean childrenArrayOpen = false; - - private boolean childNode = false; - - private boolean tagClosed = false; - - public JsonTag(String tagName) { - data.append("[\"" + tagName + "\""); - } - - private void closeTag() { - if (!tagClosed) { - data.append(attributesAsJsonObject()); - data.append(getData()); - // Writes the end (closing) tag - data.append("]"); - tagClosed = true; - } - } - - public String getJSON() { - if (!tagClosed) { - closeTag(); - } - return data.toString(); - } - - public void openChildrenArray() { - if (!childrenArrayOpen) { - // append("c : ["); - childrenArrayOpen = true; - // firstField = true; - } - } - - public void closeChildrenArray() { - // append("]"); - // firstField = false; - } - - public void setChildNode(boolean b) { - childNode = b; - } - - public boolean isChildNode() { - return childNode; - } - - public String startField() { - if (firstField) { - firstField = false; - return ""; - } else { - return ","; - } - } - - /** - * - * @param s - * json string, object or array - */ - public void addData(String s) { - children.add(s); - } - - public String getData() { - final StringBuilder buf = new StringBuilder(); - final Iterator<Object> it = children.iterator(); - while (it.hasNext()) { - buf.append(startField()); - buf.append(it.next()); - } - return buf.toString(); - } - - public void addAttribute(String jsonNode) { - attr.add(jsonNode); - } - - private String attributesAsJsonObject() { - final StringBuilder buf = new StringBuilder(); - buf.append(startField()); - buf.append("{"); - for (final Iterator<Object> iter = attr.iterator(); iter.hasNext();) { - final String element = (String) iter.next(); - buf.append(element); - if (iter.hasNext()) { - buf.append(","); - } - } - buf.append(tag.variablesAsJsonObject()); - buf.append("}"); - return buf.toString(); - } - - public void addVariable(Variable v) { - variables.add(v); - } - - private String variablesAsJsonObject() { - if (variables.size() == 0) { - return ""; - } - final StringBuilder buf = new StringBuilder(); - buf.append(startField()); - buf.append("\"v\":{"); - final Iterator<Object> iter = variables.iterator(); - while (iter.hasNext()) { - final Variable element = (Variable) iter.next(); - buf.append(element.getJsonPresentation()); - if (iter.hasNext()) { - buf.append(","); - } - } - buf.append("}"); - return buf.toString(); - } - } - - abstract class Variable implements Serializable { - - String name; - - public abstract String getJsonPresentation(); - } - - class BooleanVariable extends Variable implements Serializable { - boolean value; - - public BooleanVariable(VariableOwner owner, String name, boolean v) { - value = v; - this.name = name; - } - - @Override - public String getJsonPresentation() { - return "\"" + name + "\":" + (value == true ? "true" : "false"); - } - - } - - class StringVariable extends Variable implements Serializable { - String value; - - public StringVariable(VariableOwner owner, String name, String v) { - value = v; - this.name = name; - } - - @Override - public String getJsonPresentation() { - return "\"" + name + "\":\"" + value + "\""; - } - - } - - class IntVariable extends Variable implements Serializable { - int value; - - public IntVariable(VariableOwner owner, String name, int v) { - value = v; - this.name = name; - } - - @Override - public String getJsonPresentation() { - return "\"" + name + "\":" + value; - } - } - - class LongVariable extends Variable implements Serializable { - long value; - - public LongVariable(VariableOwner owner, String name, long v) { - value = v; - this.name = name; - } - - @Override - public String getJsonPresentation() { - return "\"" + name + "\":" + value; - } - } - - class FloatVariable extends Variable implements Serializable { - float value; - - public FloatVariable(VariableOwner owner, String name, float v) { - value = v; - this.name = name; - } - - @Override - public String getJsonPresentation() { - return "\"" + name + "\":" + value; - } - } - - class DoubleVariable extends Variable implements Serializable { - double value; - - public DoubleVariable(VariableOwner owner, String name, double v) { - value = v; - this.name = name; - } - - @Override - public String getJsonPresentation() { - return "\"" + name + "\":" + value; - } - } - - class ArrayVariable extends Variable implements Serializable { - String[] value; - - public ArrayVariable(VariableOwner owner, String name, String[] v) { - value = v; - this.name = name; - } - - @Override - public String getJsonPresentation() { - StringBuilder sb = new StringBuilder(); - sb.append("\""); - sb.append(name); - sb.append("\":["); - for (int i = 0; i < value.length;) { - sb.append("\""); - sb.append(escapeJSON(value[i])); - sb.append("\""); - i++; - if (i < value.length) { - sb.append(","); - } - } - sb.append("]"); - return sb.toString(); - } - } - - public Set<Object> getUsedResources() { - return usedResources; - } - - @Override - @SuppressWarnings("unchecked") - public String getTag(ClientConnector clientConnector) { - Class<? extends ClientConnector> clientConnectorClass = clientConnector - .getClass(); - while (clientConnectorClass.isAnonymousClass()) { - clientConnectorClass = (Class<? extends ClientConnector>) clientConnectorClass - .getSuperclass(); - } - Class<?> clazz = clientConnectorClass; - while (!usedClientConnectors.contains(clazz) - && clazz.getSuperclass() != null - && ClientConnector.class.isAssignableFrom(clazz)) { - usedClientConnectors.add((Class<? extends ClientConnector>) clazz); - clazz = clazz.getSuperclass(); - } - return manager.getTagForType(clientConnectorClass); - } - - Collection<Class<? extends ClientConnector>> getUsedClientConnectors() { - return usedClientConnectors; - } - - @Override - public void addVariable(VariableOwner owner, String name, - StreamVariable value) throws PaintException { - String url = manager.getStreamVariableTargetUrl( - (ClientConnector) owner, name, value); - if (url != null) { - addVariable(owner, name, url); - } // else { //NOP this was just a cleanup by component } - - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.PaintTarget#isFullRepaint() - */ - - @Override - public boolean isFullRepaint() { - return !cacheEnabled; - } - - private static final Logger getLogger() { - return Logger.getLogger(JsonPaintTarget.class.getName()); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java b/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java deleted file mode 100644 index 9dba05d2c1..0000000000 --- a/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java +++ /dev/null @@ -1,38 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.util.HashMap; -import java.util.Map; - -import com.vaadin.shared.communication.MethodInvocation; -import com.vaadin.terminal.gwt.client.ApplicationConnection; - -public class LegacyChangeVariablesInvocation extends MethodInvocation { - private Map<String, Object> variableChanges = new HashMap<String, Object>(); - - public LegacyChangeVariablesInvocation(String connectorId, - String variableName, Object value) { - super(connectorId, ApplicationConnection.UPDATE_VARIABLE_INTERFACE, - ApplicationConnection.UPDATE_VARIABLE_METHOD); - setVariableChange(variableName, value); - } - - public static boolean isLegacyVariableChange(String interfaceName, - String methodName) { - return ApplicationConnection.UPDATE_VARIABLE_METHOD - .equals(interfaceName) - && ApplicationConnection.UPDATE_VARIABLE_METHOD - .equals(methodName); - } - - public void setVariableChange(String name, Object value) { - variableChanges.put(name, value); - } - - public Map<String, Object> getVariableChanges() { - return variableChanges; - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/NoInputStreamException.java b/src/com/vaadin/terminal/gwt/server/NoInputStreamException.java deleted file mode 100644 index 70c3add858..0000000000 --- a/src/com/vaadin/terminal/gwt/server/NoInputStreamException.java +++ /dev/null @@ -1,9 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -@SuppressWarnings("serial") -public class NoInputStreamException extends Exception { - -} diff --git a/src/com/vaadin/terminal/gwt/server/NoOutputStreamException.java b/src/com/vaadin/terminal/gwt/server/NoOutputStreamException.java deleted file mode 100644 index e4db8453b0..0000000000 --- a/src/com/vaadin/terminal/gwt/server/NoOutputStreamException.java +++ /dev/null @@ -1,9 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -@SuppressWarnings("serial") -public class NoOutputStreamException extends Exception { - -} diff --git a/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java b/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java deleted file mode 100644 index 70505ab5f9..0000000000 --- a/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java +++ /dev/null @@ -1,398 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.File; -import java.io.Serializable; -import java.net.URL; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.portlet.ActionRequest; -import javax.portlet.ActionResponse; -import javax.portlet.EventRequest; -import javax.portlet.EventResponse; -import javax.portlet.MimeResponse; -import javax.portlet.PortletConfig; -import javax.portlet.PortletMode; -import javax.portlet.PortletModeException; -import javax.portlet.PortletResponse; -import javax.portlet.PortletSession; -import javax.portlet.PortletURL; -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; -import javax.portlet.ResourceRequest; -import javax.portlet.ResourceResponse; -import javax.portlet.StateAwareResponse; -import javax.servlet.http.HttpSessionBindingListener; -import javax.xml.namespace.QName; - -import com.vaadin.Application; -import com.vaadin.terminal.ExternalResource; -import com.vaadin.ui.Root; - -/** - * TODO Write documentation, fix JavaDoc tags. - * - * This is automatically registered as a {@link HttpSessionBindingListener} when - * {@link PortletSession#setAttribute()} is called with the context as value. - * - * @author peholmst - */ -@SuppressWarnings("serial") -public class PortletApplicationContext2 extends AbstractWebApplicationContext { - - protected Map<Application, Set<PortletListener>> portletListeners = new HashMap<Application, Set<PortletListener>>(); - - protected transient PortletSession session; - protected transient PortletConfig portletConfig; - - protected HashMap<String, Application> portletWindowIdToApplicationMap = new HashMap<String, Application>(); - - private transient PortletResponse response; - - private final Map<String, QName> eventActionDestinationMap = new HashMap<String, QName>(); - private final Map<String, Serializable> eventActionValueMap = new HashMap<String, Serializable>(); - - private final Map<String, String> sharedParameterActionNameMap = new HashMap<String, String>(); - private final Map<String, String> sharedParameterActionValueMap = new HashMap<String, String>(); - - @Override - public File getBaseDirectory() { - String resultPath = session.getPortletContext().getRealPath("/"); - if (resultPath != null) { - return new File(resultPath); - } else { - try { - final URL url = session.getPortletContext().getResource("/"); - return new File(url.getFile()); - } catch (final Exception e) { - // FIXME: Handle exception - getLogger() - .log(Level.INFO, - "Cannot access base directory, possible security issue " - + "with Application Server or Servlet Container", - e); - } - } - return null; - } - - protected PortletCommunicationManager getApplicationManager( - Application application) { - PortletCommunicationManager mgr = (PortletCommunicationManager) applicationToAjaxAppMgrMap - .get(application); - - if (mgr == null) { - // Creates a new manager - mgr = createPortletCommunicationManager(application); - applicationToAjaxAppMgrMap.put(application, mgr); - } - return mgr; - } - - protected PortletCommunicationManager createPortletCommunicationManager( - Application application) { - return new PortletCommunicationManager(application); - } - - public static PortletApplicationContext2 getApplicationContext( - PortletSession session) { - Object cxattr = session.getAttribute(PortletApplicationContext2.class - .getName()); - PortletApplicationContext2 cx = null; - // can be false also e.g. if old context comes from another - // classloader when using - // <private-session-attributes>false</private-session-attributes> - // and redeploying the portlet - see #7461 - if (cxattr instanceof PortletApplicationContext2) { - cx = (PortletApplicationContext2) cxattr; - } - if (cx == null) { - cx = new PortletApplicationContext2(); - session.setAttribute(PortletApplicationContext2.class.getName(), cx); - } - if (cx.session == null) { - cx.session = session; - } - return cx; - } - - @Override - protected void removeApplication(Application application) { - super.removeApplication(application); - // values() is backed by map, removes the key-value pair from the map - portletWindowIdToApplicationMap.values().remove(application); - } - - protected void addApplication(Application application, - String portletWindowId) { - applications.add(application); - portletWindowIdToApplicationMap.put(portletWindowId, application); - } - - public Application getApplicationForWindowId(String portletWindowId) { - return portletWindowIdToApplicationMap.get(portletWindowId); - } - - public PortletSession getPortletSession() { - return session; - } - - public PortletConfig getPortletConfig() { - return portletConfig; - } - - public void setPortletConfig(PortletConfig config) { - portletConfig = config; - } - - public void addPortletListener(Application app, PortletListener listener) { - Set<PortletListener> l = portletListeners.get(app); - if (l == null) { - l = new LinkedHashSet<PortletListener>(); - portletListeners.put(app, l); - } - l.add(listener); - } - - public void removePortletListener(Application app, PortletListener listener) { - Set<PortletListener> l = portletListeners.get(app); - if (l != null) { - l.remove(listener); - } - } - - public void firePortletRenderRequest(Application app, Root root, - RenderRequest request, RenderResponse response) { - Set<PortletListener> listeners = portletListeners.get(app); - if (listeners != null) { - for (PortletListener l : listeners) { - l.handleRenderRequest(request, new RestrictedRenderResponse( - response), root); - } - } - } - - public void firePortletActionRequest(Application app, Root root, - ActionRequest request, ActionResponse response) { - String key = request.getParameter(ActionRequest.ACTION_NAME); - if (eventActionDestinationMap.containsKey(key)) { - // this action request is only to send queued portlet events - response.setEvent(eventActionDestinationMap.get(key), - eventActionValueMap.get(key)); - // cleanup - eventActionDestinationMap.remove(key); - eventActionValueMap.remove(key); - } else if (sharedParameterActionNameMap.containsKey(key)) { - // this action request is only to set shared render parameters - response.setRenderParameter(sharedParameterActionNameMap.get(key), - sharedParameterActionValueMap.get(key)); - // cleanup - sharedParameterActionNameMap.remove(key); - sharedParameterActionValueMap.remove(key); - } else { - // normal action request, notify listeners - Set<PortletListener> listeners = portletListeners.get(app); - if (listeners != null) { - for (PortletListener l : listeners) { - l.handleActionRequest(request, response, root); - } - } - } - } - - public void firePortletEventRequest(Application app, Root root, - EventRequest request, EventResponse response) { - Set<PortletListener> listeners = portletListeners.get(app); - if (listeners != null) { - for (PortletListener l : listeners) { - l.handleEventRequest(request, response, root); - } - } - } - - public void firePortletResourceRequest(Application app, Root root, - ResourceRequest request, ResourceResponse response) { - Set<PortletListener> listeners = portletListeners.get(app); - if (listeners != null) { - for (PortletListener l : listeners) { - l.handleResourceRequest(request, response, root); - } - } - } - - public interface PortletListener extends Serializable { - - public void handleRenderRequest(RenderRequest request, - RenderResponse response, Root root); - - public void handleActionRequest(ActionRequest request, - ActionResponse response, Root root); - - public void handleEventRequest(EventRequest request, - EventResponse response, Root root); - - public void handleResourceRequest(ResourceRequest request, - ResourceResponse response, Root root); - } - - /** - * This is for use by {@link AbstractApplicationPortlet} only. - * - * TODO cleaner implementation, now "semi-static"! - * - * @param mimeResponse - */ - void setResponse(PortletResponse response) { - this.response = response; - } - - /** - * Creates a new action URL. - * - * @param action - * @return action URL or null if called outside a MimeRequest (outside a - * UIDL request or similar) - */ - public PortletURL generateActionURL(String action) { - PortletURL url = null; - if (response instanceof MimeResponse) { - url = ((MimeResponse) response).createActionURL(); - url.setParameter("javax.portlet.action", action); - } else { - return null; - } - return url; - } - - /** - * Sends a portlet event to the indicated destination. - * - * Internally, an action may be created and opened, as an event cannot be - * sent directly from all types of requests. - * - * The event destinations and values need to be kept in the context until - * sent. Any memory leaks if the action fails are limited to the session. - * - * Event names for events sent and received by a portlet need to be declared - * in portlet.xml . - * - * @param root - * a window in which a temporary action URL can be opened if - * necessary - * @param name - * event name - * @param value - * event value object that is Serializable and, if appropriate, - * has a valid JAXB annotation - */ - public void sendPortletEvent(Root root, QName name, Serializable value) - throws IllegalStateException { - if (response instanceof MimeResponse) { - String actionKey = "" + System.currentTimeMillis(); - while (eventActionDestinationMap.containsKey(actionKey)) { - actionKey = actionKey + "."; - } - PortletURL actionUrl = generateActionURL(actionKey); - if (actionUrl != null) { - eventActionDestinationMap.put(actionKey, name); - eventActionValueMap.put(actionKey, value); - root.getPage().open(new ExternalResource(actionUrl.toString())); - } else { - // this should never happen as we already know the response is a - // MimeResponse - throw new IllegalStateException( - "Portlet events can only be sent from a portlet request"); - } - } else if (response instanceof StateAwareResponse) { - ((StateAwareResponse) response).setEvent(name, value); - } else { - throw new IllegalStateException( - "Portlet events can only be sent from a portlet request"); - } - } - - /** - * Sets a shared portlet parameter. - * - * Internally, an action may be created and opened, as shared parameters - * cannot be set directly from all types of requests. - * - * The parameters and values need to be kept in the context until sent. Any - * memory leaks if the action fails are limited to the session. - * - * Shared parameters set or read by a portlet need to be declared in - * portlet.xml . - * - * @param root - * a window in which a temporary action URL can be opened if - * necessary - * @param name - * parameter identifier - * @param value - * parameter value - */ - public void setSharedRenderParameter(Root root, String name, String value) - throws IllegalStateException { - if (response instanceof MimeResponse) { - String actionKey = "" + System.currentTimeMillis(); - while (sharedParameterActionNameMap.containsKey(actionKey)) { - actionKey = actionKey + "."; - } - PortletURL actionUrl = generateActionURL(actionKey); - if (actionUrl != null) { - sharedParameterActionNameMap.put(actionKey, name); - sharedParameterActionValueMap.put(actionKey, value); - root.getPage().open(new ExternalResource(actionUrl.toString())); - } else { - // this should never happen as we already know the response is a - // MimeResponse - throw new IllegalStateException( - "Shared parameters can only be set from a portlet request"); - } - } else if (response instanceof StateAwareResponse) { - ((StateAwareResponse) response).setRenderParameter(name, value); - } else { - throw new IllegalStateException( - "Shared parameters can only be set from a portlet request"); - } - } - - /** - * Sets the portlet mode. This may trigger a new render request. - * - * Portlet modes used by a portlet need to be declared in portlet.xml . - * - * @param root - * a window in which the render URL can be opened if necessary - * @param portletMode - * the portlet mode to switch to - * @throws PortletModeException - * if the portlet mode is not allowed for some reason - * (configuration, permissions etc.) - */ - public void setPortletMode(Root root, PortletMode portletMode) - throws IllegalStateException, PortletModeException { - if (response instanceof MimeResponse) { - PortletURL url = ((MimeResponse) response).createRenderURL(); - url.setPortletMode(portletMode); - throw new RuntimeException("Root.open has not yet been implemented"); - // root.open(new ExternalResource(url.toString())); - } else if (response instanceof StateAwareResponse) { - ((StateAwareResponse) response).setPortletMode(portletMode); - } else { - throw new IllegalStateException( - "Portlet mode can only be changed from a portlet request"); - } - } - - private Logger getLogger() { - return Logger.getLogger(PortletApplicationContext2.class.getName()); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java deleted file mode 100644 index 39c27d05fe..0000000000 --- a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java +++ /dev/null @@ -1,170 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.IOException; -import java.io.InputStream; - -import javax.portlet.MimeResponse; -import javax.portlet.PortletContext; -import javax.portlet.PortletRequest; -import javax.portlet.PortletResponse; -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; -import javax.portlet.ResourceURL; - -import com.vaadin.Application; -import com.vaadin.external.json.JSONException; -import com.vaadin.external.json.JSONObject; -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.WrappedResponse; -import com.vaadin.terminal.gwt.client.ApplicationConfiguration; -import com.vaadin.ui.Root; - -/** - * TODO document me! - * - * @author peholmst - * - */ -@SuppressWarnings("serial") -public class PortletCommunicationManager extends AbstractCommunicationManager { - - public PortletCommunicationManager(Application application) { - super(application); - } - - @Override - protected BootstrapHandler createBootstrapHandler() { - return new BootstrapHandler() { - @Override - public boolean handleRequest(Application application, - WrappedRequest request, WrappedResponse response) - throws IOException { - PortletRequest portletRequest = WrappedPortletRequest.cast( - request).getPortletRequest(); - if (portletRequest instanceof RenderRequest) { - return super.handleRequest(application, request, response); - } else { - return false; - } - } - - @Override - protected String getApplicationId(BootstrapContext context) { - PortletRequest portletRequest = WrappedPortletRequest.cast( - context.getRequest()).getPortletRequest(); - /* - * We need to generate a unique ID because some portals already - * create a DIV with the portlet's Window ID as the DOM ID. - */ - return "v-" + portletRequest.getWindowID(); - } - - @Override - protected String getAppUri(BootstrapContext context) { - return getRenderResponse(context).createActionURL().toString(); - } - - private RenderResponse getRenderResponse(BootstrapContext context) { - PortletResponse response = ((WrappedPortletResponse) context - .getResponse()).getPortletResponse(); - - RenderResponse renderResponse = (RenderResponse) response; - return renderResponse; - } - - @Override - protected JSONObject getDefaultParameters(BootstrapContext context) - throws JSONException { - /* - * We need this in order to get uploads to work. TODO this is - * not needed for uploads anymore, check if this is needed for - * some other things - */ - JSONObject defaults = super.getDefaultParameters(context); - - ResourceURL portletResourceUrl = getRenderResponse(context) - .createResourceURL(); - portletResourceUrl - .setResourceID(AbstractApplicationPortlet.RESOURCE_URL_ID); - defaults.put(ApplicationConfiguration.PORTLET_RESOUCE_URL_BASE, - portletResourceUrl.toString()); - - defaults.put("pathInfo", ""); - - return defaults; - } - - @Override - protected void appendMainScriptTagContents( - BootstrapContext context, StringBuilder builder) - throws JSONException, IOException { - // fixed base theme to use - all portal pages with Vaadin - // applications will load this exactly once - String portalTheme = WrappedPortletRequest - .cast(context.getRequest()) - .getPortalProperty( - AbstractApplicationPortlet.PORTAL_PARAMETER_VAADIN_THEME); - if (portalTheme != null - && !portalTheme.equals(context.getThemeName())) { - String portalThemeUri = getThemeUri(context, portalTheme); - // XSS safe - originates from portal properties - builder.append("vaadin.loadTheme('" + portalThemeUri - + "');"); - } - - super.appendMainScriptTagContents(context, builder); - } - - @Override - protected String getMainDivStyle(BootstrapContext context) { - DeploymentConfiguration deploymentConfiguration = context - .getRequest().getDeploymentConfiguration(); - return deploymentConfiguration.getApplicationOrSystemProperty( - AbstractApplicationPortlet.PORTLET_PARAMETER_STYLE, - null); - } - - @Override - protected String getInitialUIDL(WrappedRequest request, Root root) - throws PaintException, JSONException { - return PortletCommunicationManager.this.getInitialUIDL(request, - root); - } - - @Override - protected JSONObject getApplicationParameters( - BootstrapContext context) throws JSONException, - PaintException { - JSONObject parameters = super.getApplicationParameters(context); - WrappedPortletResponse wrappedPortletResponse = (WrappedPortletResponse) context - .getResponse(); - MimeResponse portletResponse = (MimeResponse) wrappedPortletResponse - .getPortletResponse(); - ResourceURL resourceURL = portletResponse.createResourceURL(); - resourceURL.setResourceID("browserDetails"); - parameters.put("browserDetailsUrl", resourceURL.toString()); - return parameters; - } - - }; - - } - - @Override - protected InputStream getThemeResourceAsStream(Root root, String themeName, - String resource) { - PortletApplicationContext2 context = (PortletApplicationContext2) root - .getApplication().getContext(); - PortletContext portletContext = context.getPortletSession() - .getPortletContext(); - return portletContext.getResourceAsStream("/" - + AbstractApplicationPortlet.THEME_DIRECTORY_PATH + themeName - + "/" + resource); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/PortletRequestListener.java b/src/com/vaadin/terminal/gwt/server/PortletRequestListener.java deleted file mode 100644 index 8a30f5c1d4..0000000000 --- a/src/com/vaadin/terminal/gwt/server/PortletRequestListener.java +++ /dev/null @@ -1,56 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.Serializable; - -import javax.portlet.PortletRequest; -import javax.portlet.PortletResponse; -import javax.servlet.Filter; - -import com.vaadin.Application; -import com.vaadin.service.ApplicationContext.TransactionListener; -import com.vaadin.terminal.Terminal; - -/** - * An {@link Application} that implements this interface gets notified of - * request start and end by the terminal. It is quite similar to the - * {@link HttpServletRequestListener}, but the parameters are Portlet specific. - * If an Application is deployed as both a Servlet and a Portlet, one most - * likely needs to implement both. - * <p> - * Only JSR 286 style Portlets are supported. - * <p> - * The interface can be used for several helper tasks including: - * <ul> - * <li>Opening and closing database connections - * <li>Implementing {@link ThreadLocal} - * <li>Inter-portlet communication - * </ul> - * <p> - * Alternatives for implementing similar features are are Servlet {@link Filter} - * s and {@link TransactionListener}s in Vaadin. - * - * @since 6.2 - * @see HttpServletRequestListener - */ -public interface PortletRequestListener extends Serializable { - - /** - * This method is called before {@link Terminal} applies the request to - * Application. - * - * @param requestData - * the {@link PortletRequest} about to change Application state - */ - public void onRequestStart(PortletRequest request, PortletResponse response); - - /** - * This method is called at the end of each request. - * - * @param requestData - * the {@link PortletRequest} - */ - public void onRequestEnd(PortletRequest request, PortletResponse response); -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/RequestTimer.java b/src/com/vaadin/terminal/gwt/server/RequestTimer.java deleted file mode 100644 index 6c0edec466..0000000000 --- a/src/com/vaadin/terminal/gwt/server/RequestTimer.java +++ /dev/null @@ -1,43 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.Serializable; - -/** - * Times the handling of requests and stores the information as an attribute in - * the request. The timing info is later passed on to the client in the UIDL and - * the client provides JavaScript API for accessing this data from e.g. - * TestBench. - * - * @author Jonatan Kronqvist / Vaadin Ltd - */ -public class RequestTimer implements Serializable { - private long requestStartTime = 0; - - /** - * Starts the timing of a request. This should be called before any - * processing of the request. - */ - public void start() { - requestStartTime = System.nanoTime(); - } - - /** - * Stops the timing of a request. This should be called when all processing - * of a request has finished. - * - * @param context - */ - public void stop(AbstractWebApplicationContext context) { - // Measure and store the total handling time. This data can be - // used in TestBench 3 tests. - long time = (System.nanoTime() - requestStartTime) / 1000000; - - // The timings must be stored in the context, since a new - // RequestTimer is created for every request. - context.setLastRequestTime(time); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/ResourceReference.java b/src/com/vaadin/terminal/gwt/server/ResourceReference.java deleted file mode 100644 index 2104ad4b87..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ResourceReference.java +++ /dev/null @@ -1,67 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import com.vaadin.Application; -import com.vaadin.shared.communication.URLReference; -import com.vaadin.terminal.ApplicationResource; -import com.vaadin.terminal.ExternalResource; -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.ThemeResource; - -public class ResourceReference extends URLReference { - - private Resource resource; - - public ResourceReference(Resource resource) { - this.resource = resource; - } - - public Resource getResource() { - return resource; - } - - @Override - public String getURL() { - if (resource instanceof ExternalResource) { - return ((ExternalResource) resource).getURL(); - } else if (resource instanceof ApplicationResource) { - final ApplicationResource r = (ApplicationResource) resource; - final Application a = r.getApplication(); - if (a == null) { - throw new RuntimeException( - "An ApplicationResource (" - + r.getClass().getName() - + " must be attached to an application when it is sent to the client."); - } - final String uri = a.getRelativeLocation(r); - return uri; - } else if (resource instanceof ThemeResource) { - final String uri = "theme://" - + ((ThemeResource) resource).getResourceId(); - return uri; - } else { - throw new RuntimeException(getClass().getSimpleName() - + " does not support resources of type: " - + resource.getClass().getName()); - } - - } - - public static ResourceReference create(Resource resource) { - if (resource == null) { - return null; - } else { - return new ResourceReference(resource); - } - } - - public static Resource getResource(URLReference reference) { - if (reference == null) { - return null; - } - assert reference instanceof ResourceReference; - return ((ResourceReference) reference).getResource(); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/RestrictedRenderResponse.java b/src/com/vaadin/terminal/gwt/server/RestrictedRenderResponse.java deleted file mode 100644 index 9fdffbf9a5..0000000000 --- a/src/com/vaadin/terminal/gwt/server/RestrictedRenderResponse.java +++ /dev/null @@ -1,172 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.Serializable; -import java.util.Collection; -import java.util.Locale; - -import javax.portlet.CacheControl; -import javax.portlet.PortletMode; -import javax.portlet.PortletURL; -import javax.portlet.RenderResponse; -import javax.portlet.ResourceURL; -import javax.servlet.http.Cookie; - -import org.w3c.dom.DOMException; -import org.w3c.dom.Element; - -/** - * Read-only wrapper for a {@link RenderResponse}. - * - * Only for use by {@link PortletApplicationContext} and - * {@link PortletApplicationContext2}. - */ -class RestrictedRenderResponse implements RenderResponse, Serializable { - - private RenderResponse response; - - RestrictedRenderResponse(RenderResponse response) { - this.response = response; - } - - @Override - public void addProperty(String key, String value) { - response.addProperty(key, value); - } - - @Override - public PortletURL createActionURL() { - return response.createActionURL(); - } - - @Override - public PortletURL createRenderURL() { - return response.createRenderURL(); - } - - @Override - public String encodeURL(String path) { - return response.encodeURL(path); - } - - @Override - public void flushBuffer() throws IOException { - // NOP - // TODO throw? - } - - @Override - public int getBufferSize() { - return response.getBufferSize(); - } - - @Override - public String getCharacterEncoding() { - return response.getCharacterEncoding(); - } - - @Override - public String getContentType() { - return response.getContentType(); - } - - @Override - public Locale getLocale() { - return response.getLocale(); - } - - @Override - public String getNamespace() { - return response.getNamespace(); - } - - @Override - public OutputStream getPortletOutputStream() throws IOException { - // write forbidden - return null; - } - - @Override - public PrintWriter getWriter() throws IOException { - // write forbidden - return null; - } - - @Override - public boolean isCommitted() { - return response.isCommitted(); - } - - @Override - public void reset() { - // NOP - // TODO throw? - } - - @Override - public void resetBuffer() { - // NOP - // TODO throw? - } - - @Override - public void setBufferSize(int size) { - // NOP - // TODO throw? - } - - @Override - public void setContentType(String type) { - // NOP - // TODO throw? - } - - @Override - public void setProperty(String key, String value) { - response.setProperty(key, value); - } - - @Override - public void setTitle(String title) { - response.setTitle(title); - } - - @Override - public void setNextPossiblePortletModes(Collection<PortletMode> portletModes) { - // NOP - // TODO throw? - } - - @Override - public ResourceURL createResourceURL() { - return response.createResourceURL(); - } - - @Override - public CacheControl getCacheControl() { - return response.getCacheControl(); - } - - @Override - public void addProperty(Cookie cookie) { - // NOP - // TODO throw? - } - - @Override - public void addProperty(String key, Element element) { - // NOP - // TODO throw? - } - - @Override - public Element createElement(String tagName) throws DOMException { - // NOP - return null; - } -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/RpcManager.java b/src/com/vaadin/terminal/gwt/server/RpcManager.java deleted file mode 100644 index 026c847e2b..0000000000 --- a/src/com/vaadin/terminal/gwt/server/RpcManager.java +++ /dev/null @@ -1,48 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.Serializable; - -/** - * Server side RPC manager that can invoke methods based on RPC calls received - * from the client. - * - * @since 7.0 - */ -public interface RpcManager extends Serializable { - public void applyInvocation(ServerRpcMethodInvocation invocation) - throws RpcInvocationException; - - /** - * Wrapper exception for exceptions which occur during invocation of an RPC - * call - * - * @author Vaadin Ltd - * @version @VERSION@ - * @since 7.0 - * - */ - public static class RpcInvocationException extends Exception { - - public RpcInvocationException() { - super(); - } - - public RpcInvocationException(String message, Throwable cause) { - super(message, cause); - } - - public RpcInvocationException(String message) { - super(message); - } - - public RpcInvocationException(Throwable cause) { - super(cause); - } - - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/RpcTarget.java b/src/com/vaadin/terminal/gwt/server/RpcTarget.java deleted file mode 100644 index b280f5c6b5..0000000000 --- a/src/com/vaadin/terminal/gwt/server/RpcTarget.java +++ /dev/null @@ -1,28 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.Serializable; - -import com.vaadin.terminal.VariableOwner; - -/** - * Marker interface for server side classes that can receive RPC calls. - * - * This plays a role similar to that of {@link VariableOwner}. - * - * @since 7.0 - */ -public interface RpcTarget extends Serializable { - /** - * Returns the RPC manager instance to use when receiving calls for an RPC - * interface. - * - * @param rpcInterface - * interface for which the call was made - * @return RpcManager or null if none found for the interface - */ - public RpcManager getRpcManager(Class<?> rpcInterface); -} diff --git a/src/com/vaadin/terminal/gwt/server/ServerRpcManager.java b/src/com/vaadin/terminal/gwt/server/ServerRpcManager.java deleted file mode 100644 index 1c7af82a36..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ServerRpcManager.java +++ /dev/null @@ -1,142 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.vaadin.shared.Connector; - -/** - * Server side RPC manager that handles RPC calls coming from the client. - * - * Each {@link RpcTarget} (typically a {@link ClientConnector}) should have its - * own instance of {@link ServerRpcManager} if it wants to receive RPC calls - * from the client. - * - * @since 7.0 - */ -public class ServerRpcManager<T> implements RpcManager { - - private final T implementation; - private final Class<T> rpcInterface; - - private static final Map<Class<?>, Class<?>> boxedTypes = new HashMap<Class<?>, Class<?>>(); - static { - try { - Class<?>[] boxClasses = new Class<?>[] { Boolean.class, Byte.class, - Short.class, Character.class, Integer.class, Long.class, - Float.class, Double.class }; - for (Class<?> boxClass : boxClasses) { - Field typeField = boxClass.getField("TYPE"); - Class<?> primitiveType = (Class<?>) typeField.get(boxClass); - boxedTypes.put(primitiveType, boxClass); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - /** - * Create a RPC manager for an RPC target. - * - * @param target - * RPC call target (normally a {@link Connector}) - * @param implementation - * RPC interface implementation for the target - * @param rpcInterface - * RPC interface type - */ - public ServerRpcManager(T implementation, Class<T> rpcInterface) { - this.implementation = implementation; - this.rpcInterface = rpcInterface; - } - - /** - * Invoke a method in a server side RPC target class. This method is to be - * used by the RPC framework and unit testing tools only. - * - * @param target - * non-null target of the RPC call - * @param invocation - * method invocation to perform - * @throws RpcInvocationException - */ - public static void applyInvocation(RpcTarget target, - ServerRpcMethodInvocation invocation) throws RpcInvocationException { - RpcManager manager = target.getRpcManager(invocation - .getInterfaceClass()); - if (manager != null) { - manager.applyInvocation(invocation); - } else { - getLogger() - .log(Level.WARNING, - "RPC call received for RpcTarget " - + target.getClass().getName() - + " (" - + invocation.getConnectorId() - + ") but the target has not registered any RPC interfaces"); - } - } - - /** - * Returns the RPC interface implementation for the RPC target. - * - * @return RPC interface implementation - */ - protected T getImplementation() { - return implementation; - } - - /** - * Returns the RPC interface type managed by this RPC manager instance. - * - * @return RPC interface type - */ - protected Class<T> getRpcInterface() { - return rpcInterface; - } - - /** - * Invoke a method in a server side RPC target class. This method is to be - * used by the RPC framework and unit testing tools only. - * - * @param invocation - * method invocation to perform - */ - @Override - public void applyInvocation(ServerRpcMethodInvocation invocation) - throws RpcInvocationException { - Method method = invocation.getMethod(); - Class<?>[] parameterTypes = method.getParameterTypes(); - Object[] args = new Object[parameterTypes.length]; - Object[] arguments = invocation.getParameters(); - for (int i = 0; i < args.length; i++) { - // no conversion needed for basic cases - // Class<?> type = parameterTypes[i]; - // if (type.isPrimitive()) { - // type = boxedTypes.get(type); - // } - args[i] = arguments[i]; - } - try { - method.invoke(implementation, args); - } catch (Exception e) { - throw new RpcInvocationException("Unable to invoke method " - + invocation.getMethodName() + " in " - + invocation.getInterfaceName(), e); - } - } - - private static Logger getLogger() { - return Logger.getLogger(ServerRpcManager.class.getName()); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/ServerRpcMethodInvocation.java b/src/com/vaadin/terminal/gwt/server/ServerRpcMethodInvocation.java deleted file mode 100644 index ff81a27596..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ServerRpcMethodInvocation.java +++ /dev/null @@ -1,113 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.lang.reflect.Method; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import com.vaadin.shared.communication.MethodInvocation; -import com.vaadin.shared.communication.ServerRpc; - -public class ServerRpcMethodInvocation extends MethodInvocation { - - private static final Map<String, Method> invocationMethodCache = new ConcurrentHashMap<String, Method>( - 128, 0.75f, 1); - - private final Method method; - - private Class<? extends ServerRpc> interfaceClass; - - public ServerRpcMethodInvocation(String connectorId, String interfaceName, - String methodName, int parameterCount) { - super(connectorId, interfaceName, methodName); - - interfaceClass = findClass(); - method = findInvocationMethod(interfaceClass, methodName, - parameterCount); - } - - private Class<? extends ServerRpc> findClass() { - try { - Class<?> rpcInterface = Class.forName(getInterfaceName()); - if (!ServerRpc.class.isAssignableFrom(rpcInterface)) { - throw new IllegalArgumentException("The interface " - + getInterfaceName() + "is not a server RPC interface."); - } - return (Class<? extends ServerRpc>) rpcInterface; - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException("The server RPC interface " - + getInterfaceName() + " could not be found", e); - } finally { - - } - } - - public Class<? extends ServerRpc> getInterfaceClass() { - return interfaceClass; - } - - public Method getMethod() { - return method; - } - - /** - * Tries to find the method from the cache or alternatively by invoking - * {@link #doFindInvocationMethod(Class, String, int)} and updating the - * cache. - * - * @param targetType - * @param methodName - * @param parameterCount - * @return - */ - private Method findInvocationMethod(Class<?> targetType, String methodName, - int parameterCount) { - // TODO currently only using method name and number of parameters as the - // signature - String signature = targetType.getName() + "." + methodName + "(" - + parameterCount; - Method invocationMethod = invocationMethodCache.get(signature); - - if (invocationMethod == null) { - invocationMethod = doFindInvocationMethod(targetType, methodName, - parameterCount); - - if (invocationMethod != null) { - invocationMethodCache.put(signature, invocationMethod); - } - } - - if (invocationMethod == null) { - throw new IllegalStateException("Can't find method " + methodName - + " with " + parameterCount + " parameters in " - + targetType.getName()); - } - - return invocationMethod; - } - - /** - * Tries to find the method from the class by looping through available - * methods. - * - * @param targetType - * @param methodName - * @param parameterCount - * @return - */ - private Method doFindInvocationMethod(Class<?> targetType, - String methodName, int parameterCount) { - Method[] methods = targetType.getMethods(); - for (Method method : methods) { - Class<?>[] parameterTypes = method.getParameterTypes(); - if (method.getName().equals(methodName) - && parameterTypes.length == parameterCount) { - return method; - } - } - return null; - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java b/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java deleted file mode 100644 index 2a1dc31897..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.vaadin.terminal.gwt.server; - -import java.io.Serializable; - -import com.vaadin.Application; -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.ui.Root; - -/* - @VaadinApache2LicenseForJavaFiles@ - */ - -class ServletPortletHelper implements Serializable { - public static final String UPLOAD_URL_PREFIX = "APP/UPLOAD/"; - - public static class ApplicationClassException extends Exception { - - public ApplicationClassException(String message, Throwable cause) { - super(message, cause); - } - - public ApplicationClassException(String message) { - super(message); - } - } - - static Class<? extends Application> getApplicationClass( - DeploymentConfiguration deploymentConfiguration) - throws ApplicationClassException { - String applicationParameter = deploymentConfiguration - .getInitParameters().getProperty("application"); - String rootParameter = deploymentConfiguration.getInitParameters() - .getProperty(Application.ROOT_PARAMETER); - ClassLoader classLoader = deploymentConfiguration.getClassLoader(); - - if (applicationParameter == null) { - - // Validate the parameter value - verifyRootClass(rootParameter, classLoader); - - // Application can be used if a valid rootLayout is defined - return Application.class; - } - - try { - return (Class<? extends Application>) classLoader - .loadClass(applicationParameter); - } catch (final ClassNotFoundException e) { - throw new ApplicationClassException( - "Failed to load application class: " + applicationParameter, - e); - } - } - - private static void verifyRootClass(String className, - ClassLoader classLoader) throws ApplicationClassException { - if (className == null) { - throw new ApplicationClassException(Application.ROOT_PARAMETER - + " init parameter not defined"); - } - - // Check that the root layout class can be found - try { - Class<?> rootClass = classLoader.loadClass(className); - if (!Root.class.isAssignableFrom(rootClass)) { - throw new ApplicationClassException(className - + " does not implement Root"); - } - // Try finding a default constructor, else throw exception - rootClass.getConstructor(); - } catch (ClassNotFoundException e) { - throw new ApplicationClassException(className - + " could not be loaded", e); - } catch (SecurityException e) { - throw new ApplicationClassException("Could not access " + className - + " class", e); - } catch (NoSuchMethodException e) { - throw new ApplicationClassException(className - + " doesn't have a public no-args constructor"); - } - } - - private static boolean hasPathPrefix(WrappedRequest request, String prefix) { - String pathInfo = request.getRequestPathInfo(); - - if (pathInfo == null) { - return false; - } - - if (!prefix.startsWith("/")) { - prefix = '/' + prefix; - } - - if (pathInfo.startsWith(prefix)) { - return true; - } - - return false; - } - - public static boolean isFileUploadRequest(WrappedRequest request) { - return hasPathPrefix(request, UPLOAD_URL_PREFIX); - } - - public static boolean isConnectorResourceRequest(WrappedRequest request) { - return hasPathPrefix(request, - ApplicationConnection.CONNECTOR_RESOURCE_PREFIX + "/"); - } - - public static boolean isUIDLRequest(WrappedRequest request) { - return hasPathPrefix(request, ApplicationConnection.UIDL_REQUEST_PATH); - } - - public static boolean isApplicationResourceRequest(WrappedRequest request) { - return hasPathPrefix(request, ApplicationConnection.APP_REQUEST_PATH); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/SessionExpiredException.java b/src/com/vaadin/terminal/gwt/server/SessionExpiredException.java deleted file mode 100644 index 37b76de443..0000000000 --- a/src/com/vaadin/terminal/gwt/server/SessionExpiredException.java +++ /dev/null @@ -1,9 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -@SuppressWarnings("serial") -public class SessionExpiredException extends Exception { - -} diff --git a/src/com/vaadin/terminal/gwt/server/StreamingEndEventImpl.java b/src/com/vaadin/terminal/gwt/server/StreamingEndEventImpl.java deleted file mode 100644 index 0d4963bd7d..0000000000 --- a/src/com/vaadin/terminal/gwt/server/StreamingEndEventImpl.java +++ /dev/null @@ -1,16 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import com.vaadin.terminal.StreamVariable.StreamingEndEvent; - -@SuppressWarnings("serial") -final class StreamingEndEventImpl extends AbstractStreamingEvent implements - StreamingEndEvent { - - public StreamingEndEventImpl(String filename, String type, long totalBytes) { - super(filename, type, totalBytes, totalBytes); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/StreamingErrorEventImpl.java b/src/com/vaadin/terminal/gwt/server/StreamingErrorEventImpl.java deleted file mode 100644 index 6ab3df2789..0000000000 --- a/src/com/vaadin/terminal/gwt/server/StreamingErrorEventImpl.java +++ /dev/null @@ -1,25 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import com.vaadin.terminal.StreamVariable.StreamingErrorEvent; - -@SuppressWarnings("serial") -final class StreamingErrorEventImpl extends AbstractStreamingEvent implements - StreamingErrorEvent { - - private final Exception exception; - - public StreamingErrorEventImpl(final String filename, final String type, - long contentLength, long bytesReceived, final Exception exception) { - super(filename, type, contentLength, bytesReceived); - this.exception = exception; - } - - @Override - public final Exception getException() { - return exception; - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/StreamingProgressEventImpl.java b/src/com/vaadin/terminal/gwt/server/StreamingProgressEventImpl.java deleted file mode 100644 index cfa7a1b98d..0000000000 --- a/src/com/vaadin/terminal/gwt/server/StreamingProgressEventImpl.java +++ /dev/null @@ -1,17 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import com.vaadin.terminal.StreamVariable.StreamingProgressEvent; - -@SuppressWarnings("serial") -final class StreamingProgressEventImpl extends AbstractStreamingEvent implements - StreamingProgressEvent { - - public StreamingProgressEventImpl(final String filename, final String type, - long contentLength, long bytesReceived) { - super(filename, type, contentLength, bytesReceived); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/StreamingStartEventImpl.java b/src/com/vaadin/terminal/gwt/server/StreamingStartEventImpl.java deleted file mode 100644 index 274d05e111..0000000000 --- a/src/com/vaadin/terminal/gwt/server/StreamingStartEventImpl.java +++ /dev/null @@ -1,28 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import com.vaadin.terminal.StreamVariable.StreamingStartEvent; - -@SuppressWarnings("serial") -final class StreamingStartEventImpl extends AbstractStreamingEvent implements - StreamingStartEvent { - - private boolean disposed; - - public StreamingStartEventImpl(final String filename, final String type, - long contentLength) { - super(filename, type, contentLength, 0); - } - - @Override - public void disposeStreamVariable() { - disposed = true; - } - - boolean isDisposed() { - return disposed; - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/SystemMessageException.java b/src/com/vaadin/terminal/gwt/server/SystemMessageException.java deleted file mode 100644 index d15ff8a7ef..0000000000 --- a/src/com/vaadin/terminal/gwt/server/SystemMessageException.java +++ /dev/null @@ -1,57 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -@SuppressWarnings("serial") -public class SystemMessageException extends RuntimeException { - - /** - * Cause of the method exception - */ - private Throwable cause; - - /** - * Constructs a new <code>SystemMessageException</code> with the specified - * detail message. - * - * @param msg - * the detail message. - */ - public SystemMessageException(String msg) { - super(msg); - } - - /** - * Constructs a new <code>SystemMessageException</code> with the specified - * detail message and cause. - * - * @param msg - * the detail message. - * @param cause - * the cause of the exception. - */ - public SystemMessageException(String msg, Throwable cause) { - super(msg, cause); - } - - /** - * Constructs a new <code>SystemMessageException</code> from another - * exception. - * - * @param cause - * the cause of the exception. - */ - public SystemMessageException(Throwable cause) { - this.cause = cause; - } - - /** - * @see java.lang.Throwable#getCause() - */ - @Override - public Throwable getCause() { - return cause; - } - -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/UnsupportedBrowserHandler.java b/src/com/vaadin/terminal/gwt/server/UnsupportedBrowserHandler.java deleted file mode 100644 index 5248af595e..0000000000 --- a/src/com/vaadin/terminal/gwt/server/UnsupportedBrowserHandler.java +++ /dev/null @@ -1,89 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.IOException; -import java.io.Writer; - -import com.vaadin.Application; -import com.vaadin.terminal.RequestHandler; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.WrappedResponse; - -/** - * A {@link RequestHandler} that presents an informative page if the browser in - * use is unsupported. Recognizes Chrome Frame and allow it to be used. - * - * <p> - * This handler is usually added to the application by - * {@link AbstractCommunicationManager}. - * </p> - */ -@SuppressWarnings("serial") -public class UnsupportedBrowserHandler implements RequestHandler { - - /** Cookie used to ignore browser checks */ - public static final String FORCE_LOAD_COOKIE = "vaadinforceload=1"; - - @Override - public boolean handleRequest(Application application, - WrappedRequest request, WrappedResponse response) - throws IOException { - - if (request.getBrowserDetails() != null) { - // Check if the browser is supported - // If Chrome Frame is available we'll assume it's ok - WebBrowser b = request.getBrowserDetails().getWebBrowser(); - if (b.isTooOldToFunctionProperly() && !b.isChromeFrameCapable()) { - // bypass if cookie set - String c = request.getHeader("Cookie"); - if (c == null || !c.contains(FORCE_LOAD_COOKIE)) { - writeBrowserTooOldPage(request, response); - return true; // request handled - } - } - } - - return false; // pass to next handler - } - - /** - * Writes a page encouraging the user to upgrade to a more current browser. - * - * @param request - * @param response - * @throws IOException - */ - protected void writeBrowserTooOldPage(WrappedRequest request, - WrappedResponse response) throws IOException { - Writer page = response.getWriter(); - WebBrowser b = request.getBrowserDetails().getWebBrowser(); - - page.write("<html><body><h1>I'm sorry, but your browser is not supported</h1>" - + "<p>The version (" - + b.getBrowserMajorVersion() - + "." - + b.getBrowserMinorVersion() - + ") of the browser you are using " - + " is outdated and not supported.</p>" - + "<p>You should <b>consider upgrading</b> to a more up-to-date browser.</p> " - + "<p>The most popular browsers are <b>" - + " <a href=\"https://www.google.com/chrome\">Chrome</a>," - + " <a href=\"http://www.mozilla.com/firefox\">Firefox</a>," - + (b.isWindows() ? " <a href=\"http://windows.microsoft.com/en-US/internet-explorer/downloads/ie\">Internet Explorer</a>," - : "") - + " <a href=\"http://www.opera.com/browser\">Opera</a>" - + " and <a href=\"http://www.apple.com/safari\">Safari</a>.</b><br/>" - + "Upgrading to the latest version of one of these <b>will make the web safer, faster and better looking.</b></p>" - + (b.isIE() ? "<script type=\"text/javascript\" src=\"http://ajax.googleapis.com/ajax/libs/chrome-frame/1/CFInstall.min.js\"></script>" - + "<p>If you can not upgrade your browser, please consider trying <a onclick=\"CFInstall.check({mode:'overlay'});return false;\" href=\"http://www.google.com/chromeframe\">Chrome Frame</a>.</p>" - : "") // - + "<p><sub><a onclick=\"document.cookie='" - + FORCE_LOAD_COOKIE - + "';window.location.reload();return false;\" href=\"#\">Continue without updating</a> (not recommended)</sub></p>" - + "</body>\n" + "</html>"); - - page.close(); - } -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/UploadException.java b/src/com/vaadin/terminal/gwt/server/UploadException.java deleted file mode 100644 index 58253da0fb..0000000000 --- a/src/com/vaadin/terminal/gwt/server/UploadException.java +++ /dev/null @@ -1,15 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -@SuppressWarnings("serial") -public class UploadException extends Exception { - public UploadException(Exception e) { - super("Upload failed", e); - } - - public UploadException(String msg) { - super(msg); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/VaadinContext.java b/src/com/vaadin/terminal/gwt/server/VaadinContext.java deleted file mode 100644 index f03044a872..0000000000 --- a/src/com/vaadin/terminal/gwt/server/VaadinContext.java +++ /dev/null @@ -1,61 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.lang.reflect.Method; -import java.util.Iterator; - -import com.vaadin.event.EventRouter; -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.tools.ReflectTools; - -public class VaadinContext { - private static final Method BOOTSTRAP_GENERATE_METHOD = ReflectTools - .findMethod(BootstrapListener.class, "modifyBootstrap", - BootstrapResponse.class); - - private final DeploymentConfiguration deploymentConfiguration; - - private final EventRouter eventRouter = new EventRouter(); - - public VaadinContext(DeploymentConfiguration deploymentConfiguration) { - this.deploymentConfiguration = deploymentConfiguration; - deploymentConfiguration.setVaadinContext(this); - } - - public DeploymentConfiguration getDeploymentConfiguration() { - return deploymentConfiguration; - } - - public void init() { - VaadinContextEvent event = new VaadinContextEvent(this); - Iterator<VaadinContextListener> listeners = deploymentConfiguration - .getContextListeners(); - while (listeners.hasNext()) { - VaadinContextListener listener = listeners.next(); - listener.contextCreated(event); - } - } - - public void destroy() { - VaadinContextEvent event = new VaadinContextEvent(this); - Iterator<VaadinContextListener> listeners = deploymentConfiguration - .getContextListeners(); - while (listeners.hasNext()) { - VaadinContextListener listener = listeners.next(); - listener.contextDestoryed(event); - } - } - - public void addBootstrapListener(BootstrapListener listener) { - eventRouter.addListener(BootstrapResponse.class, listener, - BOOTSTRAP_GENERATE_METHOD); - } - - public void fireModifyBootstrapEvent(BootstrapResponse bootstrapResponse) { - eventRouter.fireEvent(bootstrapResponse); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/VaadinContextEvent.java b/src/com/vaadin/terminal/gwt/server/VaadinContextEvent.java deleted file mode 100644 index 239490433c..0000000000 --- a/src/com/vaadin/terminal/gwt/server/VaadinContextEvent.java +++ /dev/null @@ -1,19 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.util.EventObject; - -public class VaadinContextEvent extends EventObject { - - public VaadinContextEvent(VaadinContext source) { - super(source); - } - - public VaadinContext getVaadinContext() { - return (VaadinContext) getSource(); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/VaadinContextListener.java b/src/com/vaadin/terminal/gwt/server/VaadinContextListener.java deleted file mode 100644 index 5e379d9b91..0000000000 --- a/src/com/vaadin/terminal/gwt/server/VaadinContextListener.java +++ /dev/null @@ -1,13 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.util.EventListener; - -public interface VaadinContextListener extends EventListener { - public void contextCreated(VaadinContextEvent event); - - public void contextDestoryed(VaadinContextEvent event); -} diff --git a/src/com/vaadin/terminal/gwt/server/WebApplicationContext.java b/src/com/vaadin/terminal/gwt/server/WebApplicationContext.java deleted file mode 100644 index 36c08b2ed9..0000000000 --- a/src/com/vaadin/terminal/gwt/server/WebApplicationContext.java +++ /dev/null @@ -1,180 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.File; -import java.util.Enumeration; -import java.util.HashMap; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpSessionBindingEvent; -import javax.servlet.http.HttpSessionBindingListener; - -import com.vaadin.Application; - -/** - * Web application context for Vaadin applications. - * - * This is automatically added as a {@link HttpSessionBindingListener} when - * added to a {@link HttpSession}. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.1 - */ -@SuppressWarnings("serial") -public class WebApplicationContext extends AbstractWebApplicationContext { - - protected transient HttpSession session; - private transient boolean reinitializingSession = false; - - /** - * Stores a reference to the currentRequest. Null it not inside a request. - */ - private transient Object currentRequest = null; - - /** - * Creates a new Web Application Context. - * - */ - protected WebApplicationContext() { - - } - - @Override - protected void startTransaction(Application application, Object request) { - currentRequest = request; - super.startTransaction(application, request); - } - - @Override - protected void endTransaction(Application application, Object request) { - super.endTransaction(application, request); - currentRequest = null; - } - - @Override - public void valueUnbound(HttpSessionBindingEvent event) { - if (!reinitializingSession) { - // Avoid closing the application if we are only reinitializing the - // session. Closing the application would cause the state to be lost - // and a new application to be created, which is not what we want. - super.valueUnbound(event); - } - } - - /** - * Discards the current session and creates a new session with the same - * contents. The purpose of this is to introduce a new session key in order - * to avoid session fixation attacks. - */ - @SuppressWarnings("unchecked") - public void reinitializeSession() { - - HttpSession oldSession = getHttpSession(); - - // Stores all attributes (security key, reference to this context - // instance) so they can be added to the new session - HashMap<String, Object> attrs = new HashMap<String, Object>(); - for (Enumeration<String> e = oldSession.getAttributeNames(); e - .hasMoreElements();) { - String name = e.nextElement(); - attrs.put(name, oldSession.getAttribute(name)); - } - - // Invalidate the current session, set flag to avoid call to - // valueUnbound - reinitializingSession = true; - oldSession.invalidate(); - reinitializingSession = false; - - // Create a new session - HttpSession newSession = ((HttpServletRequest) currentRequest) - .getSession(); - - // Restores all attributes (security key, reference to this context - // instance) - for (String name : attrs.keySet()) { - newSession.setAttribute(name, attrs.get(name)); - } - - // Update the "current session" variable - session = newSession; - } - - /** - * Gets the application context base directory. - * - * @see com.vaadin.service.ApplicationContext#getBaseDirectory() - */ - @Override - public File getBaseDirectory() { - final String realPath = ApplicationServlet.getResourcePath( - session.getServletContext(), "/"); - if (realPath == null) { - return null; - } - return new File(realPath); - } - - /** - * Gets the http-session application is running in. - * - * @return HttpSession this application context resides in. - */ - public HttpSession getHttpSession() { - return session; - } - - /** - * Gets the application context for an HttpSession. - * - * @param session - * the HTTP session. - * @return the application context for HttpSession. - */ - static public WebApplicationContext getApplicationContext( - HttpSession session) { - WebApplicationContext cx = (WebApplicationContext) session - .getAttribute(WebApplicationContext.class.getName()); - if (cx == null) { - cx = new WebApplicationContext(); - session.setAttribute(WebApplicationContext.class.getName(), cx); - } - if (cx.session == null) { - cx.session = session; - } - return cx; - } - - protected void addApplication(Application application) { - applications.add(application); - } - - /** - * Gets communication manager for an application. - * - * If this application has not been running before, a new manager is - * created. - * - * @param application - * @return CommunicationManager - */ - public CommunicationManager getApplicationManager(Application application, - AbstractApplicationServlet servlet) { - CommunicationManager mgr = (CommunicationManager) applicationToAjaxAppMgrMap - .get(application); - - if (mgr == null) { - // Creates new manager - mgr = servlet.createCommunicationManager(application); - applicationToAjaxAppMgrMap.put(application, mgr); - } - return mgr; - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/WebBrowser.java b/src/com/vaadin/terminal/gwt/server/WebBrowser.java deleted file mode 100644 index 4b92b12b66..0000000000 --- a/src/com/vaadin/terminal/gwt/server/WebBrowser.java +++ /dev/null @@ -1,462 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.util.Date; -import java.util.Locale; - -import com.vaadin.shared.VBrowserDetails; -import com.vaadin.terminal.Terminal; -import com.vaadin.terminal.WrappedRequest; - -/** - * Class that provides information about the web browser the user is using. - * Provides information such as browser name and version, screen resolution and - * IP address. - * - * @author Vaadin Ltd. - * @version @VERSION@ - */ -public class WebBrowser implements Terminal { - - private int screenHeight = 0; - private int screenWidth = 0; - private String browserApplication = null; - private Locale locale; - private String address; - private boolean secureConnection; - private int timezoneOffset = 0; - private int rawTimezoneOffset = 0; - private int dstSavings; - private boolean dstInEffect; - private boolean touchDevice; - - private VBrowserDetails browserDetails; - private long clientServerTimeDelta; - - /** - * There is no default-theme for this terminal type. - * - * @return Always returns null. - */ - - @Override - public String getDefaultTheme() { - return null; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Terminal#getScreenHeight() - */ - - @Override - public int getScreenHeight() { - return screenHeight; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Terminal#getScreenWidth() - */ - - @Override - public int getScreenWidth() { - return screenWidth; - } - - /** - * Get the browser user-agent string. - * - * @return The raw browser userAgent string - */ - public String getBrowserApplication() { - return browserApplication; - } - - /** - * Gets the IP-address of the web browser. If the application is running - * inside a portlet, this method will return null. - * - * @return IP-address in 1.12.123.123 -format - */ - public String getAddress() { - return address; - } - - /** Get the default locate of the browser. */ - public Locale getLocale() { - return locale; - } - - /** Is the connection made using HTTPS? */ - public boolean isSecureConnection() { - return secureConnection; - } - - /** - * Tests whether the user is using Firefox. - * - * @return true if the user is using Firefox, false if the user is not using - * Firefox or if no information on the browser is present - */ - public boolean isFirefox() { - if (browserDetails == null) { - return false; - } - - return browserDetails.isFirefox(); - } - - /** - * Tests whether the user is using Internet Explorer. - * - * @return true if the user is using Internet Explorer, false if the user is - * not using Internet Explorer or if no information on the browser - * is present - */ - public boolean isIE() { - if (browserDetails == null) { - return false; - } - - return browserDetails.isIE(); - } - - /** - * Tests whether the user is using Safari. - * - * @return true if the user is using Safari, false if the user is not using - * Safari or if no information on the browser is present - */ - public boolean isSafari() { - if (browserDetails == null) { - return false; - } - - return browserDetails.isSafari(); - } - - /** - * Tests whether the user is using Opera. - * - * @return true if the user is using Opera, false if the user is not using - * Opera or if no information on the browser is present - */ - public boolean isOpera() { - if (browserDetails == null) { - return false; - } - - return browserDetails.isOpera(); - } - - /** - * Tests whether the user is using Chrome. - * - * @return true if the user is using Chrome, false if the user is not using - * Chrome or if no information on the browser is present - */ - public boolean isChrome() { - if (browserDetails == null) { - return false; - } - - return browserDetails.isChrome(); - } - - /** - * Tests whether the user is using Chrome Frame. - * - * @return true if the user is using Chrome Frame, false if the user is not - * using Chrome or if no information on the browser is present - */ - public boolean isChromeFrame() { - if (browserDetails == null) { - return false; - } - - return browserDetails.isChromeFrame(); - } - - /** - * Tests whether the user's browser is Chrome Frame capable. - * - * @return true if the user can use Chrome Frame, false if the user can not - * or if no information on the browser is present - */ - public boolean isChromeFrameCapable() { - if (browserDetails == null) { - return false; - } - - return browserDetails.isChromeFrameCapable(); - } - - /** - * Gets the major version of the browser the user is using. - * - * <p> - * Note that Internet Explorer in IE7 compatibility mode might return 8 in - * some cases even though it should return 7. - * </p> - * - * @return The major version of the browser or -1 if not known. - */ - public int getBrowserMajorVersion() { - if (browserDetails == null) { - return -1; - } - - return browserDetails.getBrowserMajorVersion(); - } - - /** - * Gets the minor version of the browser the user is using. - * - * @see #getBrowserMajorVersion() - * - * @return The minor version of the browser or -1 if not known. - */ - public int getBrowserMinorVersion() { - if (browserDetails == null) { - return -1; - } - - return browserDetails.getBrowserMinorVersion(); - } - - /** - * Tests whether the user is using Linux. - * - * @return true if the user is using Linux, false if the user is not using - * Linux or if no information on the browser is present - */ - public boolean isLinux() { - return browserDetails.isLinux(); - } - - /** - * Tests whether the user is using Mac OS X. - * - * @return true if the user is using Mac OS X, false if the user is not - * using Mac OS X or if no information on the browser is present - */ - public boolean isMacOSX() { - return browserDetails.isMacOSX(); - } - - /** - * Tests whether the user is using Windows. - * - * @return true if the user is using Windows, false if the user is not using - * Windows or if no information on the browser is present - */ - public boolean isWindows() { - return browserDetails.isWindows(); - } - - /** - * Returns the browser-reported TimeZone offset in milliseconds from GMT. - * This includes possible daylight saving adjustments, to figure out which - * TimeZone the user actually might be in, see - * {@link #getRawTimezoneOffset()}. - * - * @see WebBrowser#getRawTimezoneOffset() - * @return timezone offset in milliseconds, 0 if not available - */ - public Integer getTimezoneOffset() { - return timezoneOffset; - } - - /** - * Returns the browser-reported TimeZone offset in milliseconds from GMT - * ignoring possible daylight saving adjustments that may be in effect in - * the browser. - * <p> - * You can use this to figure out which TimeZones the user could actually be - * in by calling {@link TimeZone#getAvailableIDs(int)}. - * </p> - * <p> - * If {@link #getRawTimezoneOffset()} and {@link #getTimezoneOffset()} - * returns the same value, the browser is either in a zone that does not - * currently have daylight saving time, or in a zone that never has daylight - * saving time. - * </p> - * - * @return timezone offset in milliseconds excluding DST, 0 if not available - */ - public Integer getRawTimezoneOffset() { - return rawTimezoneOffset; - } - - /** - * Gets the difference in minutes between the browser's GMT TimeZone and - * DST. - * - * @return the amount of minutes that the TimeZone shifts when DST is in - * effect - */ - public int getDSTSavings() { - return dstSavings; - } - - /** - * Determines whether daylight savings time (DST) is currently in effect in - * the region of the browser or not. - * - * @return true if the browser resides at a location that currently is in - * DST - */ - public boolean isDSTInEffect() { - return dstInEffect; - } - - /** - * Returns the current date and time of the browser. This will not be - * entirely accurate due to varying network latencies, but should provide a - * close-enough value for most cases. Also note that the returned Date - * object uses servers default time zone, not the clients. - * - * @return the current date and time of the browser. - * @see #isDSTInEffect() - * @see #getDSTSavings() - * @see #getTimezoneOffset() - */ - public Date getCurrentDate() { - return new Date(new Date().getTime() + clientServerTimeDelta); - } - - /** - * @return true if the browser is detected to support touch events - */ - public boolean isTouchDevice() { - return touchDevice; - } - - /** - * For internal use by AbstractApplicationServlet/AbstractApplicationPortlet - * only. Updates all properties in the class according to the given - * information. - * - * @param sw - * Screen width - * @param sh - * Screen height - * @param tzo - * TimeZone offset in minutes from GMT - * @param rtzo - * raw TimeZone offset in minutes from GMT (w/o DST adjustment) - * @param dstSavings - * the difference between the raw TimeZone and DST in minutes - * @param dstInEffect - * is DST currently active in the region or not? - * @param curDate - * the current date in milliseconds since the epoch - * @param touchDevice - */ - void updateClientSideDetails(String sw, String sh, String tzo, String rtzo, - String dstSavings, String dstInEffect, String curDate, - boolean touchDevice) { - if (sw != null) { - try { - screenHeight = Integer.parseInt(sh); - screenWidth = Integer.parseInt(sw); - } catch (final NumberFormatException e) { - screenHeight = screenWidth = 0; - } - } - if (tzo != null) { - try { - // browser->java conversion: min->ms, reverse sign - timezoneOffset = -Integer.parseInt(tzo) * 60 * 1000; - } catch (final NumberFormatException e) { - timezoneOffset = 0; // default gmt+0 - } - } - if (rtzo != null) { - try { - // browser->java conversion: min->ms, reverse sign - rawTimezoneOffset = -Integer.parseInt(rtzo) * 60 * 1000; - } catch (final NumberFormatException e) { - rawTimezoneOffset = 0; // default gmt+0 - } - } - if (dstSavings != null) { - try { - // browser->java conversion: min->ms - this.dstSavings = Integer.parseInt(dstSavings) * 60 * 1000; - } catch (final NumberFormatException e) { - this.dstSavings = 0; // default no savings - } - } - if (dstInEffect != null) { - this.dstInEffect = Boolean.parseBoolean(dstInEffect); - } - if (curDate != null) { - try { - long curTime = Long.parseLong(curDate); - clientServerTimeDelta = curTime - new Date().getTime(); - } catch (final NumberFormatException e) { - clientServerTimeDelta = 0; - } - } - this.touchDevice = touchDevice; - - } - - /** - * For internal use by AbstractApplicationServlet/AbstractApplicationPortlet - * only. Updates all properties in the class according to the given - * information. - * - * @param request - * the wrapped request to read the information from - */ - void updateRequestDetails(WrappedRequest request) { - locale = request.getLocale(); - address = request.getRemoteAddr(); - secureConnection = request.isSecure(); - String agent = request.getHeader("user-agent"); - - if (agent != null) { - browserApplication = agent; - browserDetails = new VBrowserDetails(agent); - } - - if (request.getParameter("sw") != null) { - updateClientSideDetails(request.getParameter("sw"), - request.getParameter("sh"), request.getParameter("tzo"), - request.getParameter("rtzo"), request.getParameter("dstd"), - request.getParameter("dston"), - request.getParameter("curdate"), - request.getParameter("td") != null); - } - } - - /** - * Checks if the browser is so old that it simply won't work with a Vaadin - * application. Can be used to redirect to an alternative page, show - * alternative content or similar. - * - * When this method returns true chances are very high that the browser - * won't work and it does not make sense to direct the user to the Vaadin - * application. - * - * @return true if the browser won't work, false if not the browser is - * supported or might work - */ - public boolean isTooOldToFunctionProperly() { - if (browserDetails == null) { - // Don't know, so assume it will work - return false; - } - - return browserDetails.isTooOldToFunctionProperly(); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java b/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java deleted file mode 100644 index cf58f398af..0000000000 --- a/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java +++ /dev/null @@ -1,118 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; - -import com.vaadin.Application; -import com.vaadin.terminal.CombinedRequest; -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.WrappedRequest; - -/** - * Wrapper for {@link HttpServletRequest}. - * - * @author Vaadin Ltd. - * @since 7.0 - * - * @see WrappedRequest - * @see WrappedHttpServletResponse - */ -public class WrappedHttpServletRequest extends HttpServletRequestWrapper - implements WrappedRequest { - - private final DeploymentConfiguration deploymentConfiguration; - - /** - * Wraps a http servlet request and associates with a deployment - * configuration - * - * @param request - * the http servlet request to wrap - * @param deploymentConfiguration - * the associated deployment configuration - */ - public WrappedHttpServletRequest(HttpServletRequest request, - DeploymentConfiguration deploymentConfiguration) { - super(request); - this.deploymentConfiguration = deploymentConfiguration; - } - - @Override - public String getRequestPathInfo() { - return getPathInfo(); - } - - @Override - public int getSessionMaxInactiveInterval() { - return getSession().getMaxInactiveInterval(); - } - - @Override - public Object getSessionAttribute(String name) { - return getSession().getAttribute(name); - } - - @Override - public void setSessionAttribute(String name, Object attribute) { - getSession().setAttribute(name, attribute); - } - - /** - * Gets the original, unwrapped HTTP servlet request. - * - * @return the servlet request - */ - public HttpServletRequest getHttpServletRequest() { - return this; - } - - @Override - public DeploymentConfiguration getDeploymentConfiguration() { - return deploymentConfiguration; - } - - @Override - public BrowserDetails getBrowserDetails() { - return new BrowserDetails() { - @Override - public String getUriFragment() { - return null; - } - - @Override - public String getWindowName() { - return null; - } - - @Override - public WebBrowser getWebBrowser() { - WebApplicationContext context = (WebApplicationContext) Application - .getCurrent().getContext(); - return context.getBrowser(); - } - }; - } - - /** - * Helper method to get a <code>WrappedHttpServletRequest</code> from a - * <code>WrappedRequest</code>. Aside from casting, this method also takes - * care of situations where there's another level of wrapping. - * - * @param request - * a wrapped request - * @return a wrapped http servlet request - * @throws ClassCastException - * if the wrapped request doesn't wrap a http servlet request - */ - public static WrappedHttpServletRequest cast(WrappedRequest request) { - if (request instanceof CombinedRequest) { - CombinedRequest combinedRequest = (CombinedRequest) request; - request = combinedRequest.getSecondRequest(); - } - return (WrappedHttpServletRequest) request; - } -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/WrappedHttpServletResponse.java b/src/com/vaadin/terminal/gwt/server/WrappedHttpServletResponse.java deleted file mode 100644 index 32b2f352a8..0000000000 --- a/src/com/vaadin/terminal/gwt/server/WrappedHttpServletResponse.java +++ /dev/null @@ -1,75 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; - -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.WrappedResponse; - -/** - * Wrapper for {@link HttpServletResponse}. - * - * @author Vaadin Ltd. - * @since 7.0 - * - * @see WrappedResponse - * @see WrappedHttpServletRequest - */ -public class WrappedHttpServletResponse extends HttpServletResponseWrapper - implements WrappedResponse { - - private DeploymentConfiguration deploymentConfiguration; - - /** - * Wraps a http servlet response and an associated deployment configuration - * - * @param response - * the http servlet response to wrap - * @param deploymentConfiguration - * the associated deployment configuration - */ - public WrappedHttpServletResponse(HttpServletResponse response, - DeploymentConfiguration deploymentConfiguration) { - super(response); - this.deploymentConfiguration = deploymentConfiguration; - } - - /** - * Gets the original unwrapped <code>HttpServletResponse</code> - * - * @return the unwrapped response - */ - public HttpServletResponse getHttpServletResponse() { - return this; - } - - @Override - public void setCacheTime(long milliseconds) { - doSetCacheTime(this, milliseconds); - } - - // Implementation shared with WrappedPortletResponse - static void doSetCacheTime(WrappedResponse response, long milliseconds) { - if (milliseconds <= 0) { - response.setHeader("Cache-Control", "no-cache"); - response.setHeader("Pragma", "no-cache"); - response.setDateHeader("Expires", 0); - } else { - response.setHeader("Cache-Control", "max-age=" + milliseconds - / 1000); - response.setDateHeader("Expires", System.currentTimeMillis() - + milliseconds); - // Required to apply caching in some Tomcats - response.setHeader("Pragma", "cache"); - } - } - - @Override - public DeploymentConfiguration getDeploymentConfiguration() { - return deploymentConfiguration; - } -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java b/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java deleted file mode 100644 index a3fa172034..0000000000 --- a/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java +++ /dev/null @@ -1,217 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Locale; -import java.util.Map; - -import javax.portlet.ClientDataRequest; -import javax.portlet.PortletRequest; -import javax.portlet.ResourceRequest; - -import com.vaadin.Application; -import com.vaadin.terminal.CombinedRequest; -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.gwt.client.ApplicationConnection; - -/** - * Wrapper for {@link PortletRequest} and its subclasses. - * - * @author Vaadin Ltd. - * @since 7.0 - * - * @see WrappedRequest - * @see WrappedPortletResponse - */ -public class WrappedPortletRequest implements WrappedRequest { - - private final PortletRequest request; - private final DeploymentConfiguration deploymentConfiguration; - - /** - * Wraps a portlet request and an associated deployment configuration - * - * @param request - * the portlet request to wrap - * @param deploymentConfiguration - * the associated deployment configuration - */ - public WrappedPortletRequest(PortletRequest request, - DeploymentConfiguration deploymentConfiguration) { - this.request = request; - this.deploymentConfiguration = deploymentConfiguration; - } - - @Override - public Object getAttribute(String name) { - return request.getAttribute(name); - } - - @Override - public int getContentLength() { - try { - return ((ClientDataRequest) request).getContentLength(); - } catch (ClassCastException e) { - throw new IllegalStateException( - "Content lenght only available for ClientDataRequests"); - } - } - - @Override - public InputStream getInputStream() throws IOException { - try { - return ((ClientDataRequest) request).getPortletInputStream(); - } catch (ClassCastException e) { - throw new IllegalStateException( - "Input data only available for ClientDataRequests"); - } - } - - @Override - public String getParameter(String name) { - return request.getParameter(name); - } - - @Override - public Map<String, String[]> getParameterMap() { - return request.getParameterMap(); - } - - @Override - public void setAttribute(String name, Object o) { - request.setAttribute(name, o); - } - - @Override - public String getRequestPathInfo() { - if (request instanceof ResourceRequest) { - ResourceRequest resourceRequest = (ResourceRequest) request; - String resourceID = resourceRequest.getResourceID(); - if (AbstractApplicationPortlet.RESOURCE_URL_ID.equals(resourceID)) { - String resourcePath = resourceRequest - .getParameter(ApplicationConnection.V_RESOURCE_PATH); - return resourcePath; - } - return resourceID; - } else { - return null; - } - } - - @Override - public int getSessionMaxInactiveInterval() { - return request.getPortletSession().getMaxInactiveInterval(); - } - - @Override - public Object getSessionAttribute(String name) { - return request.getPortletSession().getAttribute(name); - } - - @Override - public void setSessionAttribute(String name, Object attribute) { - request.getPortletSession().setAttribute(name, attribute); - } - - /** - * Gets the original, unwrapped portlet request. - * - * @return the unwrapped portlet request - */ - public PortletRequest getPortletRequest() { - return request; - } - - @Override - public String getContentType() { - try { - return ((ResourceRequest) request).getContentType(); - } catch (ClassCastException e) { - throw new IllegalStateException( - "Content type only available for ResourceRequests"); - } - } - - @Override - public BrowserDetails getBrowserDetails() { - return new BrowserDetails() { - @Override - public String getUriFragment() { - return null; - } - - @Override - public String getWindowName() { - return null; - } - - @Override - public WebBrowser getWebBrowser() { - PortletApplicationContext2 context = (PortletApplicationContext2) Application - .getCurrent().getContext(); - return context.getBrowser(); - } - }; - } - - @Override - public Locale getLocale() { - return request.getLocale(); - } - - @Override - public String getRemoteAddr() { - return null; - } - - @Override - public boolean isSecure() { - return request.isSecure(); - } - - @Override - public String getHeader(String string) { - return null; - } - - /** - * Reads a portal property from the portal context of the wrapped request. - * - * @param name - * a string with the name of the portal property to get - * @return a string with the value of the property, or <code>null</code> if - * the property is not defined - */ - public String getPortalProperty(String name) { - return request.getPortalContext().getProperty(name); - } - - @Override - public DeploymentConfiguration getDeploymentConfiguration() { - return deploymentConfiguration; - } - - /** - * Helper method to get a <code>WrappedPortlettRequest</code> from a - * <code>WrappedRequest</code>. Aside from casting, this method also takes - * care of situations where there's another level of wrapping. - * - * @param request - * a wrapped request - * @return a wrapped portlet request - * @throws ClassCastException - * if the wrapped request doesn't wrap a portlet request - */ - public static WrappedPortletRequest cast(WrappedRequest request) { - if (request instanceof CombinedRequest) { - CombinedRequest combinedRequest = (CombinedRequest) request; - request = combinedRequest.getSecondRequest(); - } - return (WrappedPortletRequest) request; - } -} diff --git a/src/com/vaadin/terminal/gwt/server/WrappedPortletResponse.java b/src/com/vaadin/terminal/gwt/server/WrappedPortletResponse.java deleted file mode 100644 index f7ecf26f3c..0000000000 --- a/src/com/vaadin/terminal/gwt/server/WrappedPortletResponse.java +++ /dev/null @@ -1,111 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; - -import javax.portlet.MimeResponse; -import javax.portlet.PortletResponse; -import javax.portlet.ResourceResponse; - -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.WrappedResponse; - -/** - * Wrapper for {@link PortletResponse} and its subclasses. - * - * @author Vaadin Ltd. - * @since 7.0 - * - * @see WrappedResponse - * @see WrappedPortletRequest - */ -public class WrappedPortletResponse implements WrappedResponse { - private static final DateFormat HTTP_DATE_FORMAT = new SimpleDateFormat( - "EEE, dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH); - static { - HTTP_DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT")); - } - - private final PortletResponse response; - private DeploymentConfiguration deploymentConfiguration; - - /** - * Wraps a portlet response and an associated deployment configuration - * - * @param response - * the portlet response to wrap - * @param deploymentConfiguration - * the associated deployment configuration - */ - public WrappedPortletResponse(PortletResponse response, - DeploymentConfiguration deploymentConfiguration) { - this.response = response; - this.deploymentConfiguration = deploymentConfiguration; - } - - @Override - public OutputStream getOutputStream() throws IOException { - return ((MimeResponse) response).getPortletOutputStream(); - } - - /** - * Gets the original, unwrapped portlet response. - * - * @return the unwrapped portlet response - */ - public PortletResponse getPortletResponse() { - return response; - } - - @Override - public void setContentType(String type) { - ((MimeResponse) response).setContentType(type); - } - - @Override - public PrintWriter getWriter() throws IOException { - return ((MimeResponse) response).getWriter(); - } - - @Override - public void setStatus(int responseStatus) { - response.setProperty(ResourceResponse.HTTP_STATUS_CODE, - Integer.toString(responseStatus)); - } - - @Override - public void setHeader(String name, String value) { - response.setProperty(name, value); - } - - @Override - public void setDateHeader(String name, long timestamp) { - response.setProperty(name, HTTP_DATE_FORMAT.format(new Date(timestamp))); - } - - @Override - public void setCacheTime(long milliseconds) { - WrappedHttpServletResponse.doSetCacheTime(this, milliseconds); - } - - @Override - public void sendError(int errorCode, String message) throws IOException { - setStatus(errorCode); - getWriter().write(message); - } - - @Override - public DeploymentConfiguration getDeploymentConfiguration() { - return deploymentConfiguration; - } -}
\ No newline at end of file |