* Handling is now based on a list of RequestHandlers in VaadinService * Request handling logic has been moved to VaadinService * Users can customize the list by adding own (service level) request handlers * For users specific request handlers you can still use the request handlers in VaadinSession * Deprecated RequestType - all handlers are given the opportunity to handle a request until one of them chooses to handle it. RequestType makes no sense as it does not tell which handler will handle the request. * Removed serveStaticResource which has never been used Change-Id: Ia7d088535e46430ca8adf631d3f1dd944b9d51e2tags/7.1.0.beta1
@@ -115,6 +115,12 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { | |||
@Override | |||
public boolean synchronizedHandleRequest(VaadinSession session, | |||
VaadinRequest request, VaadinResponse response) throws IOException { | |||
String pathInfo = request.getPathInfo(); | |||
if (pathInfo.startsWith("/" + ApplicationConstants.APP_PATH + "/")) { | |||
// We do not want to handle /APP requests here, instead let it fall | |||
// through and produce a 404 | |||
return false; | |||
} | |||
try { | |||
List<UIProvider> uiProviders = session.getUIProviders(); |
@@ -48,60 +48,50 @@ public class ConnectorResourceHandler implements RequestHandler { | |||
return false; | |||
} | |||
Matcher matcher = CONNECTOR_RESOURCE_PATTERN.matcher(requestPath); | |||
if (matcher.matches()) { | |||
String uiId = matcher.group(1); | |||
String cid = matcher.group(2); | |||
String key = matcher.group(3); | |||
session.lock(); | |||
UI ui; | |||
ClientConnector connector; | |||
try { | |||
ui = session.getUIById(Integer.parseInt(uiId)); | |||
if (ui == null) { | |||
return error(request, response, | |||
"Ignoring connector request for no-existent root " | |||
+ uiId); | |||
} | |||
connector = ui.getConnectorTracker().getConnector(cid); | |||
if (connector == null) { | |||
return error(request, response, | |||
"Ignoring connector request for no-existent connector " | |||
+ cid + " in root " + uiId); | |||
} | |||
if (!matcher.matches()) { | |||
return false; | |||
} | |||
String uiId = matcher.group(1); | |||
String cid = matcher.group(2); | |||
String key = matcher.group(3); | |||
} finally { | |||
session.unlock(); | |||
session.lock(); | |||
UI ui; | |||
ClientConnector connector; | |||
try { | |||
ui = session.getUIById(Integer.parseInt(uiId)); | |||
if (ui == null) { | |||
return error(request, response, | |||
"Ignoring connector request for no-existent root " | |||
+ uiId); | |||
} | |||
Map<Class<?>, CurrentInstance> oldThreadLocals = CurrentInstance | |||
.setThreadLocals(ui); | |||
try { | |||
if (!connector.handleConnectorRequest(request, response, key)) { | |||
return error(request, response, | |||
connector.getClass().getSimpleName() + " (" | |||
+ connector.getConnectorId() | |||
+ ") did not handle connector request for " | |||
+ key); | |||
} | |||
} finally { | |||
CurrentInstance.restoreThreadLocals(oldThreadLocals); | |||
connector = ui.getConnectorTracker().getConnector(cid); | |||
if (connector == null) { | |||
return error(request, response, | |||
"Ignoring connector request for no-existent connector " | |||
+ cid + " in root " + uiId); | |||
} | |||
return true; | |||
} else if (requestPath.matches('/' + ApplicationConstants.APP_PATH | |||
+ "(/.*)?")) { | |||
/* | |||
* This should be the last request handler before we get to | |||
* bootstrap logic. Prevent /APP requests from reaching bootstrap | |||
* handlers to help protect the /APP name space for framework usage. | |||
*/ | |||
return error(request, response, | |||
"Returning 404 for /APP request not yet handled."); | |||
} else { | |||
return false; | |||
} finally { | |||
session.unlock(); | |||
} | |||
Map<Class<?>, CurrentInstance> oldThreadLocals = CurrentInstance | |||
.setThreadLocals(ui); | |||
try { | |||
if (!connector.handleConnectorRequest(request, response, key)) { | |||
return error(request, response, connector.getClass() | |||
.getSimpleName() | |||
+ " (" | |||
+ connector.getConnectorId() | |||
+ ") did not handle connector request for " + key); | |||
} | |||
} finally { | |||
CurrentInstance.restoreThreadLocals(oldThreadLocals); | |||
} | |||
return true; | |||
} | |||
private static boolean error(VaadinRequest request, |
@@ -184,16 +184,14 @@ public class GAEVaadinServlet extends VaadinServlet { | |||
return; | |||
} | |||
RequestType requestType = getRequestType(request); | |||
if (requestType == RequestType.STATIC_FILE) { | |||
if (isStaticResourceRequest(request)) { | |||
// no locking needed, let superclass handle | |||
super.service(request, response); | |||
cleanSession(request); | |||
return; | |||
} | |||
if (requestType == RequestType.APP) { | |||
if (ServletPortletHelper.isAppRequest(request)) { | |||
// no locking needed, let superclass handle | |||
getApplicationContext(request, | |||
MemcacheServiceFactory.getMemcacheService()); | |||
@@ -205,7 +203,11 @@ public class GAEVaadinServlet extends VaadinServlet { | |||
final HttpSession session = request.getSession(getService() | |||
.requestCanCreateSession(request)); | |||
if (session == null) { | |||
handleServiceSessionExpired(request, response); | |||
try { | |||
getService().handleSessionExpired(request, response); | |||
} catch (ServiceException e) { | |||
throw new ServletException(e); | |||
} | |||
cleanSession(request); | |||
return; | |||
} | |||
@@ -218,19 +220,21 @@ public class GAEVaadinServlet extends VaadinServlet { | |||
// 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 (!ServletPortletHelper.isUIDLRequest(request)) { | |||
while (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); | |||
} | |||
} | |||
} | |||
@@ -65,10 +65,6 @@ public class LegacyCommunicationManager implements Serializable { | |||
// TODO PUSH move | |||
public static final String WRITE_SECURITY_TOKEN_FLAG = "writeSecurityToken"; | |||
private static final RequestHandler UNSUPPORTED_BROWSER_HANDLER = new UnsupportedBrowserHandler(); | |||
private static final RequestHandler CONNECTOR_RESOURCE_HANDLER = new ConnectorResourceHandler(); | |||
/** | |||
* TODO Document me! | |||
* | |||
@@ -112,10 +108,6 @@ public class LegacyCommunicationManager implements Serializable { | |||
*/ | |||
public LegacyCommunicationManager(VaadinSession session) { | |||
this.session = session; | |||
session.addRequestHandler(session.getService().createBootstrapHandler( | |||
session)); | |||
session.addRequestHandler(UNSUPPORTED_BROWSER_HANDLER); | |||
session.addRequestHandler(CONNECTOR_RESOURCE_HANDLER); | |||
requireLocale(session.getLocale().toString()); | |||
} | |||
@@ -17,17 +17,14 @@ package com.vaadin.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.Method; | |||
import java.net.MalformedURLException; | |||
import java.util.Enumeration; | |||
import java.util.Map; | |||
import java.util.Properties; | |||
import java.util.logging.Level; | |||
import java.util.logging.Logger; | |||
import javax.portlet.ActionRequest; | |||
@@ -46,18 +43,11 @@ 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.server.LegacyCommunicationManager.Callback; | |||
import com.vaadin.server.communication.FileUploadHandler; | |||
import com.vaadin.server.communication.HeartbeatHandler; | |||
import com.vaadin.server.communication.PortletListenerNotifier; | |||
import com.vaadin.server.communication.PublishedFileHandler; | |||
import com.vaadin.server.communication.SessionRequestHandler; | |||
import com.vaadin.server.communication.UIInitHandler; | |||
import com.vaadin.server.communication.UidlRequestHandler; | |||
import com.vaadin.server.communication.PortletDummyRequestHandler; | |||
import com.vaadin.server.communication.PortletUIInitHandler; | |||
import com.vaadin.util.CurrentInstance; | |||
/** | |||
@@ -207,24 +197,6 @@ public class VaadinPortlet extends GenericPortlet implements Constants, | |||
} | |||
public static class AbstractApplicationPortletWrapper implements Callback { | |||
private final VaadinPortlet portlet; | |||
public AbstractApplicationPortletWrapper(VaadinPortlet portlet) { | |||
this.portlet = portlet; | |||
} | |||
@Override | |||
public void criticalNotification(VaadinRequest request, | |||
VaadinResponse response, String cap, String msg, | |||
String details, String outOfSyncURL) throws IOException { | |||
portlet.criticalNotification((VaadinPortletRequest) request, | |||
(VaadinPortletResponse) 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. | |||
@@ -287,6 +259,7 @@ public class VaadinPortlet extends GenericPortlet implements Constants, | |||
vaadinService.setCurrentInstances(null, null); | |||
portletInitialized(); | |||
CurrentInstance.clearAll(); | |||
} | |||
@@ -307,8 +280,10 @@ public class VaadinPortlet extends GenericPortlet implements Constants, | |||
/** | |||
* @author Vaadin Ltd | |||
* | |||
* @deprecated As of 7.0. Will likely change or be removed in a future | |||
* version | |||
* @deprecated As of 7.0. This is no longer used and only provided for | |||
* backwards compatibility. Each {@link RequestHandler} can | |||
* individually decide whether it wants to handle a request or | |||
* not. | |||
*/ | |||
@Deprecated | |||
protected enum RequestType { | |||
@@ -319,8 +294,10 @@ public class VaadinPortlet extends GenericPortlet implements Constants, | |||
* @param vaadinRequest | |||
* @return | |||
* | |||
* @deprecated As of 7.0. Will likely change or be removed in a future | |||
* version | |||
* @deprecated As of 7.0. This is no longer used and only provided for | |||
* backwards compatibility. Each {@link RequestHandler} can | |||
* individually decide whether it wants to handle a request or | |||
* not. | |||
*/ | |||
@Deprecated | |||
protected RequestType getRequestType(VaadinPortletRequest vaadinRequest) { | |||
@@ -331,7 +308,7 @@ public class VaadinPortlet extends GenericPortlet implements Constants, | |||
ResourceRequest resourceRequest = (ResourceRequest) request; | |||
if (ServletPortletHelper.isUIDLRequest(vaadinRequest)) { | |||
return RequestType.UIDL; | |||
} else if (isBrowserDetailsRequest(resourceRequest)) { | |||
} else if (PortletUIInitHandler.isUIInitRequest(vaadinRequest)) { | |||
return RequestType.BROWSER_DETAILS; | |||
} else if (ServletPortletHelper.isFileUploadRequest(vaadinRequest)) { | |||
return RequestType.FILE_UPLOAD; | |||
@@ -342,7 +319,7 @@ public class VaadinPortlet extends GenericPortlet implements Constants, | |||
return RequestType.APP; | |||
} else if (ServletPortletHelper.isHeartbeatRequest(vaadinRequest)) { | |||
return RequestType.HEARTBEAT; | |||
} else if (isDummyRequest(resourceRequest)) { | |||
} else if (PortletDummyRequestHandler.isDummyRequest(vaadinRequest)) { | |||
return RequestType.DUMMY; | |||
} else { | |||
return RequestType.STATIC_FILE; | |||
@@ -355,16 +332,6 @@ public class VaadinPortlet extends GenericPortlet implements Constants, | |||
return RequestType.UNKNOWN; | |||
} | |||
private boolean isBrowserDetailsRequest(ResourceRequest request) { | |||
return request.getResourceID() != null | |||
&& request.getResourceID().equals("v-browserDetails"); | |||
} | |||
private boolean isDummyRequest(ResourceRequest request) { | |||
return request.getResourceID() != null | |||
&& request.getResourceID().equals("DUMMY"); | |||
} | |||
/** | |||
* @param request | |||
* @param response | |||
@@ -380,93 +347,11 @@ public class VaadinPortlet extends GenericPortlet implements Constants, | |||
CurrentInstance.clearAll(); | |||
setCurrent(this); | |||
handleRequest(createVaadinRequest(request), | |||
createVaadinResponse(response)); | |||
} | |||
protected void handleRequest(VaadinPortletRequest request, | |||
VaadinPortletResponse response) throws PortletException, | |||
IOException { | |||
getService().requestStart(request, response); | |||
VaadinPortletSession vaadinSession = null; | |||
try { | |||
AbstractApplicationPortletWrapper portletWrapper = new AbstractApplicationPortletWrapper( | |||
this); | |||
RequestType requestType = getRequestType(request); | |||
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 { | |||
try { | |||
vaadinSession = (VaadinPortletSession) getService() | |||
.findVaadinSession(request); | |||
if (vaadinSession == null) { | |||
return; | |||
} | |||
if (requestType == RequestType.PUBLISHED_FILE) { | |||
new PublishedFileHandler().handleRequest(vaadinSession, | |||
request, response); | |||
return; | |||
} else if (requestType == RequestType.HEARTBEAT) { | |||
new HeartbeatHandler().handleRequest(vaadinSession, | |||
request, response); | |||
return; | |||
} | |||
// Notify listeners | |||
new PortletListenerNotifier().handleRequest(vaadinSession, | |||
request, response); | |||
/* Handle the request */ | |||
if (requestType == RequestType.FILE_UPLOAD) { | |||
new FileUploadHandler().handleRequest(vaadinSession, | |||
request, response); | |||
return; | |||
} else if (requestType == RequestType.BROWSER_DETAILS) { | |||
new UIInitHandler().handleRequest(vaadinSession, | |||
request, response); | |||
return; | |||
} else if (requestType == RequestType.UIDL) { | |||
// Handles AJAX UIDL requests | |||
new UidlRequestHandler(portletWrapper).handleRequest( | |||
vaadinSession, request, response); | |||
return; | |||
} else { | |||
handleOtherRequest(request, response, requestType, | |||
vaadinSession, | |||
vaadinSession.getCommunicationManager()); | |||
} | |||
} catch (final SessionExpiredException e) { | |||
// TODO Figure out a better way to deal with | |||
// SessionExpiredExceptions | |||
getLogger().finest("A user session has expired"); | |||
} catch (final Throwable e) { | |||
handleServiceException(request, response, vaadinSession, e); | |||
} | |||
} | |||
} finally { | |||
getService().requestEnd(request, response, vaadinSession); | |||
getService().handleRequest(createVaadinRequest(request), | |||
createVaadinResponse(response)); | |||
} catch (ServiceException e) { | |||
throw new PortletException(e); | |||
} | |||
} | |||
@@ -498,80 +383,12 @@ public class VaadinPortlet extends GenericPortlet implements Constants, | |||
return vaadinService; | |||
} | |||
private void handleUnknownRequest(VaadinPortletRequest request, | |||
VaadinPortletResponse 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 vaadinSession | |||
* @param vaadinSession | |||
* @param communicationManager | |||
* @throws PortletException | |||
* @throws IOException | |||
* @throws MalformedURLException | |||
*/ | |||
private void handleOtherRequest(VaadinPortletRequest request, | |||
VaadinResponse response, RequestType requestType, | |||
VaadinSession vaadinSession, | |||
LegacyCommunicationManager communicationManager) | |||
throws PortletException, IOException, MalformedURLException { | |||
if (requestType == RequestType.APP || requestType == RequestType.RENDER) { | |||
if (!new SessionRequestHandler().handleRequest(vaadinSession, | |||
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().log(Level.INFO, | |||
"Requested resource [{0}] could not be found", resourceID); | |||
response.setProperty(ResourceResponse.HTTP_STATUS_CODE, | |||
Integer.toString(HttpServletResponse.SC_NOT_FOUND)); | |||
} | |||
} | |||
@Override | |||
public void processAction(ActionRequest request, ActionResponse response) | |||
throws PortletException, IOException { | |||
@@ -606,44 +423,6 @@ public class VaadinPortlet extends GenericPortlet implements Constants, | |||
handleRequest(request, response); | |||
} | |||
private void handleServiceException(VaadinPortletRequest request, | |||
VaadinPortletResponse response, VaadinSession vaadinSession, | |||
Throwable e) throws IOException, PortletException { | |||
// TODO Check that this error handler is working when running inside a | |||
// portlet | |||
if (vaadinSession != null) { | |||
vaadinSession.lock(); | |||
} | |||
try { | |||
// if this was an UIDL request, response UIDL back to client | |||
ErrorHandler errorHandler = ErrorEvent | |||
.findErrorHandler(vaadinSession); | |||
if (getRequestType(request) == RequestType.UIDL) { | |||
SystemMessages ci = getService().getSystemMessages( | |||
ServletPortletHelper.findLocale(null, vaadinSession, | |||
request), request); | |||
criticalNotification(request, response, | |||
ci.getInternalErrorCaption(), | |||
ci.getInternalErrorMessage(), null, | |||
ci.getInternalErrorURL()); | |||
if (errorHandler != null) { | |||
errorHandler.error(new ErrorEvent(e)); | |||
} | |||
} else { | |||
if (errorHandler != null) { | |||
errorHandler.error(new ErrorEvent(e)); | |||
} else { | |||
// Re-throw other exceptions | |||
throw new PortletException(e); | |||
} | |||
} | |||
} finally { | |||
if (vaadinSession != null) { | |||
vaadinSession.unlock(); | |||
} | |||
} | |||
} | |||
/** | |||
* Send notification to client's application. Used to notify client of | |||
* critical errors and session expiration due to long inactivity. Server has |
@@ -17,17 +17,23 @@ | |||
package com.vaadin.server; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.URL; | |||
import java.util.List; | |||
import java.util.logging.Level; | |||
import java.util.logging.Logger; | |||
import javax.portlet.EventRequest; | |||
import javax.portlet.PortletContext; | |||
import javax.portlet.PortletRequest; | |||
import javax.portlet.RenderRequest; | |||
import com.vaadin.server.VaadinPortlet.RequestType; | |||
import com.vaadin.server.communication.PortletBootstrapHandler; | |||
import com.vaadin.server.communication.PortletDummyRequestHandler; | |||
import com.vaadin.server.communication.PortletListenerNotifier; | |||
import com.vaadin.server.communication.PortletUIInitHandler; | |||
import com.vaadin.ui.UI; | |||
public class VaadinPortletService extends VaadinService { | |||
@@ -49,6 +55,35 @@ public class VaadinPortletService extends VaadinService { | |||
} | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see | |||
* com.vaadin.server.LegacyCommunicationManager.Callback#criticalNotification | |||
* (com.vaadin.server.VaadinRequest, com.vaadin.server.VaadinResponse, | |||
* java.lang.String, java.lang.String, java.lang.String, java.lang.String) | |||
*/ | |||
@Deprecated | |||
@Override | |||
public void criticalNotification(VaadinRequest request, | |||
VaadinResponse response, String cap, String msg, String details, | |||
String url) throws IOException { | |||
getPortlet().criticalNotification((VaadinPortletRequest) request, | |||
(VaadinPortletResponse) response, cap, msg, details, url); | |||
} | |||
@Override | |||
protected List<RequestHandler> createRequestHandlers() { | |||
List<RequestHandler> handlers = super.createRequestHandlers(); | |||
handlers.add(new PortletUIInitHandler()); | |||
handlers.add(new PortletListenerNotifier()); | |||
handlers.add(0, new PortletDummyRequestHandler()); | |||
handlers.add(0, new PortletBootstrapHandler()); | |||
return handlers; | |||
} | |||
/** | |||
* Retrieves a reference to the portlet associated with this service. | |||
* | |||
@@ -163,13 +198,19 @@ public class VaadinPortletService extends VaadinService { | |||
@Override | |||
protected boolean requestCanCreateSession(VaadinRequest request) { | |||
RequestType requestType = getRequestType(request); | |||
if (requestType == RequestType.RENDER) { | |||
if (!(request instanceof VaadinPortletRequest)) { | |||
throw new IllegalArgumentException( | |||
"Request is not a VaadinPortletRequest"); | |||
} | |||
PortletRequest portletRequest = ((VaadinPortletRequest) request) | |||
.getPortletRequest(); | |||
if (portletRequest instanceof RenderRequest) { | |||
// In most cases the first request is a render request that | |||
// renders the HTML fragment. This should create a Vaadin | |||
// session unless there is already one. | |||
return true; | |||
} else if (requestType == RequestType.EVENT) { | |||
} else if (portletRequest instanceof EventRequest) { | |||
// 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. | |||
@@ -254,8 +295,19 @@ public class VaadinPortletService extends VaadinService { | |||
return "v-" + portletRequest.getWindowID(); | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see | |||
* com.vaadin.server.VaadinService#handleSessionExpired(com.vaadin.server | |||
* .VaadinRequest, com.vaadin.server.VaadinResponse) | |||
*/ | |||
@Override | |||
protected BootstrapHandler createBootstrapHandler(VaadinSession session) { | |||
return new PortletBootstrapHandler(); | |||
protected void handleSessionExpired(VaadinRequest request, | |||
VaadinResponse response) { | |||
// TODO Figure out a better way to deal with | |||
// SessionExpiredExceptions | |||
getLogger().finest("A user session has expired"); | |||
} | |||
} |
@@ -17,6 +17,7 @@ | |||
package com.vaadin.server; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.Serializable; | |||
import java.lang.reflect.Constructor; | |||
@@ -24,7 +25,9 @@ import java.lang.reflect.Method; | |||
import java.net.MalformedURLException; | |||
import java.net.URL; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Locale; | |||
import java.util.concurrent.locks.Lock; | |||
import java.util.concurrent.locks.ReentrantLock; | |||
@@ -33,9 +36,16 @@ import java.util.logging.Logger; | |||
import javax.portlet.PortletContext; | |||
import javax.servlet.ServletContext; | |||
import javax.servlet.http.HttpServletResponse; | |||
import com.vaadin.annotations.PreserveOnRefresh; | |||
import com.vaadin.event.EventRouter; | |||
import com.vaadin.server.LegacyCommunicationManager.Callback; | |||
import com.vaadin.server.communication.FileUploadHandler; | |||
import com.vaadin.server.communication.HeartbeatHandler; | |||
import com.vaadin.server.communication.PublishedFileHandler; | |||
import com.vaadin.server.communication.SessionRequestHandler; | |||
import com.vaadin.server.communication.UidlRequestHandler; | |||
import com.vaadin.shared.ui.ui.UIConstants; | |||
import com.vaadin.ui.UI; | |||
import com.vaadin.util.CurrentInstance; | |||
@@ -49,7 +59,7 @@ import com.vaadin.util.ReflectTools; | |||
* | |||
* @since 7.0 | |||
*/ | |||
public abstract class VaadinService implements Serializable { | |||
public abstract class VaadinService implements Serializable, Callback { | |||
static final String REINITIALIZING_SESSION_MARKER = VaadinService.class | |||
.getName() + ".reinitializing"; | |||
@@ -83,6 +93,8 @@ public abstract class VaadinService implements Serializable { | |||
private ClassLoader classLoader; | |||
private final Iterable<RequestHandler> requestHandlers; | |||
/** | |||
* Creates a new vaadin service based on a deployment configuration | |||
* | |||
@@ -108,6 +120,33 @@ public abstract class VaadinService implements Serializable { | |||
+ classLoaderName, e); | |||
} | |||
} | |||
List<RequestHandler> handlers = createRequestHandlers(); | |||
Collections.reverse(handlers); | |||
requestHandlers = Collections.unmodifiableCollection(handlers); | |||
} | |||
/** | |||
* Called during initialization to add the request handlers for the service. | |||
* Note that the returned list will be reversed so the last handler will be | |||
* called first. This enables overriding this method and using add on the | |||
* returned list to add a custom request handler which overrides any | |||
* predefined handler. | |||
* | |||
* @return The list of request handlers used by this service. | |||
*/ | |||
protected List<RequestHandler> createRequestHandlers() { | |||
ArrayList<RequestHandler> handlers = new ArrayList<RequestHandler>(); | |||
handlers.add(new SessionRequestHandler()); | |||
handlers.add(new PublishedFileHandler()); | |||
handlers.add(new HeartbeatHandler()); | |||
handlers.add(new FileUploadHandler()); | |||
handlers.add(new UidlRequestHandler(this)); | |||
handlers.add(new UnsupportedBrowserHandler()); | |||
handlers.add(new ConnectorResourceHandler()); | |||
return handlers; | |||
} | |||
/** | |||
@@ -285,13 +324,6 @@ public abstract class VaadinService implements Serializable { | |||
*/ | |||
public abstract File getBaseDirectory(); | |||
/** | |||
* Creates the bootstrap handler that should be used to generate the initial | |||
* HTML bootstrapping a new {@link UI} in the given session. | |||
*/ | |||
protected abstract BootstrapHandler createBootstrapHandler( | |||
VaadinSession session); | |||
/** | |||
* Adds a listener that gets notified when a new Vaadin service session is | |||
* initialized for this service. | |||
@@ -1203,4 +1235,125 @@ public abstract class VaadinService implements Serializable { | |||
} | |||
CurrentInstance.clearAll(); | |||
} | |||
/** | |||
* Returns the request handlers that are registered with this service. The | |||
* iteration order of the returned collection is the same as the order in | |||
* which the request handlers will be invoked when a request is handled. | |||
* | |||
* @return a collection of request handlers in the order they are invoked | |||
* | |||
* @see #createRequestHandlers() | |||
* | |||
* @since 7.1 | |||
*/ | |||
public Iterable<RequestHandler> getRequestHandlers() { | |||
return requestHandlers; | |||
} | |||
/** | |||
* Handles the incoming request and writes the response into the response | |||
* object. Uses {@link #getRequestHandlers()} for handling the request. | |||
* | |||
* @param request | |||
* The incoming request | |||
* @param response | |||
* The outgoing response | |||
* @throws ServiceException | |||
* Any exception that occurs during response handling will be | |||
* wrapped in a ServiceException | |||
*/ | |||
public void handleRequest(VaadinRequest request, VaadinResponse response) | |||
throws ServiceException { | |||
requestStart(request, response); | |||
VaadinSession vaadinSession = null; | |||
try { | |||
// Find out the service session this request is related to | |||
vaadinSession = findVaadinSession(request); | |||
if (vaadinSession == null) { | |||
return; | |||
} | |||
for (RequestHandler handler : getRequestHandlers()) { | |||
if (handler.handleRequest(vaadinSession, request, response)) { | |||
return; | |||
} | |||
} | |||
// Request not handled by any RequestHandler | |||
response.sendError(HttpServletResponse.SC_NOT_FOUND, | |||
"Request was not handled by any registered handler."); | |||
} catch (final SessionExpiredException e) { | |||
handleSessionExpired(request, response); | |||
} catch (final Throwable e) { | |||
handleExceptionDuringRequest(request, response, vaadinSession, e); | |||
} finally { | |||
requestEnd(request, response, vaadinSession); | |||
} | |||
} | |||
private void handleExceptionDuringRequest(VaadinRequest request, | |||
VaadinResponse response, VaadinSession vaadinSession, Throwable t) | |||
throws ServiceException { | |||
if (vaadinSession != null) { | |||
vaadinSession.lock(); | |||
} | |||
try { | |||
ErrorHandler errorHandler = ErrorEvent | |||
.findErrorHandler(vaadinSession); | |||
// if this was an UIDL request, response UIDL back to client | |||
if (ServletPortletHelper.isUIDLRequest(request)) { | |||
SystemMessages ci = getSystemMessages( | |||
ServletPortletHelper.findLocale(null, vaadinSession, | |||
request), request); | |||
try { | |||
criticalNotification(request, response, | |||
ci.getInternalErrorCaption(), | |||
ci.getInternalErrorMessage(), null, | |||
ci.getInternalErrorURL()); | |||
} catch (IOException e) { | |||
// An exception occured while writing the response. Log | |||
// it and continue handling only the original error. | |||
getLogger() | |||
.log(Level.WARNING, | |||
"Failed to write critical notification response to the client", | |||
e); | |||
} | |||
if (errorHandler != null) { | |||
errorHandler.error(new ErrorEvent(t)); | |||
} | |||
} else { | |||
if (errorHandler != null) { | |||
errorHandler.error(new ErrorEvent(t)); | |||
} | |||
// Re-throw other exceptions | |||
throw new ServiceException(t); | |||
} | |||
} finally { | |||
if (vaadinSession != null) { | |||
vaadinSession.unlock(); | |||
} | |||
} | |||
} | |||
/** | |||
* Called when the session has expired and the request handling is therefore | |||
* aborted. | |||
* | |||
* @param request | |||
* The request | |||
* @param response | |||
* The response | |||
* @throws ServiceException | |||
* Thrown if there was any problem handling the expiration of | |||
* the session | |||
*/ | |||
protected abstract void handleSessionExpired(VaadinRequest request, | |||
VaadinResponse response) throws ServiceException; | |||
} |
@@ -39,41 +39,12 @@ import javax.servlet.http.HttpServletRequest; | |||
import javax.servlet.http.HttpServletResponse; | |||
import com.vaadin.sass.internal.ScssStylesheet; | |||
import com.vaadin.server.LegacyCommunicationManager.Callback; | |||
import com.vaadin.server.communication.FileUploadHandler; | |||
import com.vaadin.server.communication.HeartbeatHandler; | |||
import com.vaadin.server.communication.PublishedFileHandler; | |||
import com.vaadin.server.communication.SessionRequestHandler; | |||
import com.vaadin.server.communication.UIInitHandler; | |||
import com.vaadin.server.communication.UidlRequestHandler; | |||
import com.vaadin.server.communication.ServletUIInitHandler; | |||
import com.vaadin.util.CurrentInstance; | |||
@SuppressWarnings("serial") | |||
public class VaadinServlet extends HttpServlet implements Constants { | |||
private static class AbstractApplicationServletWrapper implements Callback { | |||
private final VaadinServlet servlet; | |||
public AbstractApplicationServletWrapper(VaadinServlet servlet) { | |||
this.servlet = servlet; | |||
} | |||
@Override | |||
public void criticalNotification(VaadinRequest request, | |||
VaadinResponse response, String cap, String msg, | |||
String details, String outOfSyncURL) throws IOException { | |||
servlet.criticalNotification((VaadinServletRequest) request, | |||
((VaadinServletResponse) 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 VaadinServletService servletService; | |||
/** | |||
@@ -200,7 +171,23 @@ public class VaadinServlet extends HttpServlet implements Constants { | |||
} | |||
CurrentInstance.clearAll(); | |||
setCurrent(this); | |||
service(createVaadinRequest(request), createVaadinResponse(response)); | |||
VaadinServletRequest vaadinRequest = createVaadinRequest(request); | |||
VaadinServletResponse vaadinResponse = createVaadinResponse(response); | |||
if (!ensureCookiesEnabled(vaadinRequest, vaadinResponse)) { | |||
return; | |||
} | |||
if (isStaticResourceRequest(request)) { | |||
serveStaticResources(request, response); | |||
return; | |||
} | |||
try { | |||
getService().handleRequest(vaadinRequest, vaadinResponse); | |||
} catch (ServiceException e) { | |||
throw new ServletException(e); | |||
} | |||
} | |||
/** | |||
@@ -239,73 +226,6 @@ public class VaadinServlet extends HttpServlet implements Constants { | |||
} | |||
} | |||
private void service(VaadinServletRequest request, | |||
VaadinServletResponse response) throws ServletException, | |||
IOException { | |||
getService().requestStart(request, response); | |||
VaadinSession vaadinSession = null; | |||
try { | |||
AbstractApplicationServletWrapper servletWrapper = new AbstractApplicationServletWrapper( | |||
this); | |||
RequestType requestType = getRequestType(request); | |||
if (!ensureCookiesEnabled(requestType, request, response)) { | |||
return; | |||
} | |||
if (requestType == RequestType.STATIC_FILE) { | |||
serveStaticResources(request, response); | |||
return; | |||
} | |||
try { | |||
// Find out the service session this request is related to | |||
vaadinSession = getService().findVaadinSession(request); | |||
if (vaadinSession == null) { | |||
return; | |||
} | |||
if (requestType == RequestType.PUBLISHED_FILE) { | |||
new PublishedFileHandler().handleRequest(vaadinSession, | |||
request, response); | |||
return; | |||
} else if (requestType == RequestType.HEARTBEAT) { | |||
new HeartbeatHandler().handleRequest(vaadinSession, | |||
request, response); | |||
return; | |||
} else if (requestType == RequestType.FILE_UPLOAD) { | |||
new FileUploadHandler().handleRequest(vaadinSession, | |||
request, response); | |||
return; | |||
} else if (requestType == RequestType.UIDL) { | |||
new UidlRequestHandler(servletWrapper).handleRequest( | |||
vaadinSession, request, response); | |||
return; | |||
} else if (requestType == RequestType.BROWSER_DETAILS) { | |||
// Browser details - not related to a specific UI | |||
new UIInitHandler().handleRequest(vaadinSession, request, | |||
response); | |||
return; | |||
} else if (new SessionRequestHandler().handleRequest( | |||
vaadinSession, request, response)) { | |||
return; | |||
} | |||
// Request not handled by any RequestHandler -> 404 | |||
response.sendError(HttpServletResponse.SC_NOT_FOUND); | |||
} catch (final SessionExpiredException e) { | |||
// Session has expired, notify user | |||
handleServiceSessionExpired(request, response); | |||
} catch (final Throwable e) { | |||
handleServiceException(request, response, vaadinSession, e); | |||
} | |||
} finally { | |||
getService().requestEnd(request, response, vaadinSession); | |||
} | |||
} | |||
private VaadinServletResponse createVaadinResponse( | |||
HttpServletResponse response) { | |||
return new VaadinServletResponse(response, getService()); | |||
@@ -347,10 +267,9 @@ public class VaadinServlet extends HttpServlet implements Constants { | |||
* @return false if cookies are disabled, true otherwise | |||
* @throws IOException | |||
*/ | |||
private boolean ensureCookiesEnabled(RequestType requestType, | |||
VaadinServletRequest request, VaadinServletResponse response) | |||
throws IOException { | |||
if (requestType == RequestType.UIDL) { | |||
private boolean ensureCookiesEnabled(VaadinServletRequest request, | |||
VaadinServletResponse response) throws IOException { | |||
if (ServletPortletHelper.isUIDLRequest(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 | |||
@@ -509,44 +428,6 @@ public class VaadinServlet extends HttpServlet implements Constants { | |||
return resultPath; | |||
} | |||
private void handleServiceException(VaadinServletRequest request, | |||
VaadinServletResponse response, VaadinSession vaadinSession, | |||
Throwable e) throws IOException, ServletException { | |||
if (vaadinSession != null) { | |||
vaadinSession.lock(); | |||
} | |||
try { | |||
ErrorHandler errorHandler = ErrorEvent | |||
.findErrorHandler(vaadinSession); | |||
// if this was an UIDL request, response UIDL back to client | |||
if (getRequestType(request) == RequestType.UIDL) { | |||
SystemMessages ci = getService().getSystemMessages( | |||
ServletPortletHelper.findLocale(null, vaadinSession, | |||
request), request); | |||
criticalNotification(request, response, | |||
ci.getInternalErrorCaption(), | |||
ci.getInternalErrorMessage(), null, | |||
ci.getInternalErrorURL()); | |||
if (errorHandler != null) { | |||
errorHandler.error(new ErrorEvent(e)); | |||
} | |||
} else { | |||
if (errorHandler != null) { | |||
errorHandler.error(new ErrorEvent(e)); | |||
} | |||
// Re-throw other exceptions | |||
throw new ServletException(e); | |||
} | |||
} finally { | |||
if (vaadinSession != null) { | |||
vaadinSession.unlock(); | |||
} | |||
} | |||
} | |||
/** | |||
* A helper method to strip away characters that might somehow be used for | |||
* XSS attacs. Leaves at least alphanumeric characters intact. Also removes | |||
@@ -591,68 +472,6 @@ public class VaadinServlet extends HttpServlet implements Constants { | |||
return DEFAULT_THEME_NAME; | |||
} | |||
/** | |||
* @param request | |||
* @param response | |||
* @throws IOException | |||
* @throws ServletException | |||
* | |||
* @deprecated As of 7.0. Will likely change or be removed in a future | |||
* version | |||
*/ | |||
@Deprecated | |||
void handleServiceSessionExpired(VaadinServletRequest request, | |||
VaadinServletResponse response) throws IOException, | |||
ServletException { | |||
try { | |||
SystemMessages ci = getService().getSystemMessages( | |||
ServletPortletHelper.findLocale(null, null, request), | |||
request); | |||
RequestType requestType = getRequestType(request); | |||
if (requestType == RequestType.UIDL) { | |||
/* | |||
* 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()); | |||
} else if (requestType == RequestType.HEARTBEAT) { | |||
response.sendError(HttpServletResponse.SC_GONE, | |||
"Session expired"); | |||
} else { | |||
// 'plain' http req - e.g. browser reload; | |||
// just go ahead redirect the browser | |||
String sessionExpiredURL = ci.getSessionExpiredURL(); | |||
if (sessionExpiredURL != null) { | |||
response.sendRedirect(sessionExpiredURL); | |||
} else { | |||
/* | |||
* Session expired as a result of a standard http request | |||
* and we have nowhere to redirect. Reloading would likely | |||
* cause an endless loop. This can at least happen if | |||
* refreshing a resource when the session has expired. | |||
*/ | |||
response.sendError(HttpServletResponse.SC_GONE, | |||
"Session expired"); | |||
} | |||
} | |||
} catch (SystemMessageException ee) { | |||
throw new ServletException(ee); | |||
} | |||
} | |||
private void handleServiceSecurityException(VaadinServletRequest request, | |||
VaadinServletResponse response) throws IOException, | |||
ServletException { | |||
@@ -664,14 +483,13 @@ public class VaadinServlet extends HttpServlet implements Constants { | |||
*/ | |||
SystemMessages ci = getService().getSystemMessages( | |||
request.getLocale(), request); | |||
RequestType requestType = getRequestType(request); | |||
if (requestType == RequestType.UIDL) { | |||
if (ServletPortletHelper.isUIDLRequest(request)) { | |||
// send uidl redirect | |||
criticalNotification(request, response, | |||
ci.getCommunicationErrorCaption(), | |||
ci.getCommunicationErrorMessage(), | |||
INVALID_SECURITY_KEY_MSG, ci.getCommunicationErrorURL()); | |||
} else if (requestType == RequestType.HEARTBEAT) { | |||
} else if (ServletPortletHelper.isHeartbeatRequest(request)) { | |||
response.sendError(HttpServletResponse.SC_FORBIDDEN, | |||
"Forbidden"); | |||
} else { | |||
@@ -1056,10 +874,12 @@ public class VaadinServlet extends HttpServlet implements Constants { | |||
/** | |||
* | |||
* @author Vaadin Ltd | |||
* @since 7.0.0 | |||
* @since 7.0 | |||
* | |||
* @deprecated As of 7.0. Will likely change or be removed in a future | |||
* version | |||
* @deprecated As of 7.0. This is no longer used and only provided for | |||
* backwards compatibility. Each {@link RequestHandler} can | |||
* individually decide whether it wants to handle a request or | |||
* not. | |||
*/ | |||
@Deprecated | |||
protected enum RequestType { | |||
@@ -1070,8 +890,10 @@ public class VaadinServlet extends HttpServlet implements Constants { | |||
* @param request | |||
* @return | |||
* | |||
* @deprecated As of 7.0. Will likely change or be removed in a future | |||
* version | |||
* @deprecated As of 7.0. This is no longer used and only provided for | |||
* backwards compatibility. Each {@link RequestHandler} can | |||
* individually decide whether it wants to handle a request or | |||
* not. | |||
*/ | |||
@Deprecated | |||
protected RequestType getRequestType(VaadinServletRequest request) { | |||
@@ -1079,7 +901,7 @@ public class VaadinServlet extends HttpServlet implements Constants { | |||
return RequestType.FILE_UPLOAD; | |||
} else if (ServletPortletHelper.isPublishedFileRequest(request)) { | |||
return RequestType.PUBLISHED_FILE; | |||
} else if (isBrowserDetailsRequest(request)) { | |||
} else if (ServletUIInitHandler.isUIInitRequest(request)) { | |||
return RequestType.BROWSER_DETAILS; | |||
} else if (ServletPortletHelper.isUIDLRequest(request)) { | |||
return RequestType.UIDL; | |||
@@ -1094,12 +916,7 @@ public class VaadinServlet extends HttpServlet implements Constants { | |||
} | |||
private static boolean isBrowserDetailsRequest(HttpServletRequest request) { | |||
return "POST".equals(request.getMethod()) | |||
&& request.getParameter("v-browserDetails") != null; | |||
} | |||
private boolean isStaticResourceRequest(HttpServletRequest request) { | |||
protected boolean isStaticResourceRequest(HttpServletRequest request) { | |||
String pathInfo = request.getPathInfo(); | |||
if (pathInfo == null || pathInfo.length() <= 10) { | |||
return false; | |||
@@ -1235,4 +1052,5 @@ public class VaadinServlet extends HttpServlet implements Constants { | |||
private static final Logger getLogger() { | |||
return Logger.getLogger(VaadinServlet.class.getName()); | |||
} | |||
} |
@@ -17,15 +17,19 @@ | |||
package com.vaadin.server; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.MalformedURLException; | |||
import java.net.URL; | |||
import java.util.List; | |||
import java.util.logging.Logger; | |||
import javax.servlet.ServletContext; | |||
import javax.servlet.http.HttpServletRequest; | |||
import javax.servlet.http.HttpServletResponse; | |||
import com.vaadin.server.VaadinServlet.RequestType; | |||
import com.vaadin.server.communication.ServletBootstrapHandler; | |||
import com.vaadin.server.communication.ServletUIInitHandler; | |||
import com.vaadin.ui.UI; | |||
public class VaadinServletService extends VaadinService { | |||
@@ -47,6 +51,31 @@ public class VaadinServletService extends VaadinService { | |||
} | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see | |||
* com.vaadin.server.LegacyCommunicationManager.Callback#criticalNotification | |||
* (com.vaadin.server.VaadinRequest, com.vaadin.server.VaadinResponse, | |||
* java.lang.String, java.lang.String, java.lang.String, java.lang.String) | |||
*/ | |||
@Deprecated | |||
@Override | |||
public void criticalNotification(VaadinRequest request, | |||
VaadinResponse response, String cap, String msg, String details, | |||
String url) throws IOException { | |||
getServlet().criticalNotification((VaadinServletRequest) request, | |||
(VaadinServletResponse) response, cap, msg, details, url); | |||
} | |||
@Override | |||
protected List<RequestHandler> createRequestHandlers() { | |||
List<RequestHandler> handlers = super.createRequestHandlers(); | |||
handlers.add(0, new ServletBootstrapHandler()); | |||
handlers.add(new ServletUIInitHandler()); | |||
return handlers; | |||
} | |||
/** | |||
* Retrieves a reference to the servlet associated with this service. | |||
* | |||
@@ -135,12 +164,11 @@ public class VaadinServletService extends VaadinService { | |||
@Override | |||
protected boolean requestCanCreateSession(VaadinRequest request) { | |||
RequestType requestType = getRequestType(request); | |||
if (requestType == RequestType.BROWSER_DETAILS) { | |||
if (ServletUIInitHandler.isUIInitRequest(request)) { | |||
// This is the first request if you are embedding by writing the | |||
// embedding code yourself | |||
return true; | |||
} else if (requestType == RequestType.OTHER) { | |||
} else if (isOtherRequest(request)) { | |||
/* | |||
* I.e URIs that are not RPC calls or static (theme) files. | |||
*/ | |||
@@ -150,25 +178,15 @@ public class VaadinServletService extends VaadinService { | |||
return false; | |||
} | |||
/** | |||
* Gets the request type for the request. | |||
* | |||
* @param request | |||
* the request to get a request type for | |||
* @return the request type | |||
* | |||
* @deprecated As of 7.0. Will likely change or be removed in a future | |||
* version | |||
*/ | |||
@Deprecated | |||
protected RequestType getRequestType(VaadinRequest request) { | |||
RequestType type = (RequestType) request.getAttribute(RequestType.class | |||
.getName()); | |||
if (type == null) { | |||
type = getServlet().getRequestType((VaadinServletRequest) request); | |||
request.setAttribute(RequestType.class.getName(), type); | |||
} | |||
return type; | |||
private boolean isOtherRequest(VaadinRequest request) { | |||
// TODO This should be refactored in some way. It should not be | |||
// necessary to check all these types. | |||
return (!ServletPortletHelper.isAppRequest(request) | |||
&& !ServletUIInitHandler.isUIInitRequest(request) | |||
&& !ServletPortletHelper.isFileUploadRequest(request) | |||
&& !ServletPortletHelper.isHeartbeatRequest(request) | |||
&& !ServletPortletHelper.isPublishedFileRequest(request) && !ServletPortletHelper | |||
.isUIDLRequest(request)); | |||
} | |||
@Override | |||
@@ -235,8 +253,73 @@ public class VaadinServletService extends VaadinService { | |||
return appId; | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see | |||
* com.vaadin.server.VaadinService#handleSessionExpired(com.vaadin.server | |||
* .VaadinRequest, com.vaadin.server.VaadinResponse) | |||
*/ | |||
@Override | |||
protected BootstrapHandler createBootstrapHandler(VaadinSession session) { | |||
return new ServletBootstrapHandler(); | |||
protected void handleSessionExpired(VaadinRequest request, | |||
VaadinResponse response) throws ServiceException { | |||
if (!(request instanceof VaadinServletRequest)) { | |||
throw new ServiceException(new IllegalArgumentException( | |||
"handleSessionExpired called with a non-VaadinServletRequest: " | |||
+ request.getClass().getName())); | |||
} | |||
VaadinServletRequest servletRequest = (VaadinServletRequest) request; | |||
VaadinServletResponse servletResponse = (VaadinServletResponse) response; | |||
try { | |||
SystemMessages ci = getSystemMessages( | |||
ServletPortletHelper.findLocale(null, null, request), | |||
request); | |||
if (ServletPortletHelper.isUIDLRequest(request)) { | |||
/* | |||
* Invalidate session (weird to have session if we're saying | |||
* that it's expired) | |||
* | |||
* Session must be invalidated before criticalNotification as it | |||
* commits the response. | |||
*/ | |||
servletRequest.getSession().invalidate(); | |||
// send uidl redirect | |||
criticalNotification(request, response, | |||
ci.getSessionExpiredCaption(), | |||
ci.getSessionExpiredMessage(), null, | |||
ci.getSessionExpiredURL()); | |||
} else if (ServletPortletHelper.isHeartbeatRequest(request)) { | |||
response.sendError(HttpServletResponse.SC_GONE, | |||
"Session expired"); | |||
} else { | |||
// 'plain' http req - e.g. browser reload; | |||
// just go ahead redirect the browser | |||
String sessionExpiredURL = ci.getSessionExpiredURL(); | |||
if (sessionExpiredURL != null) { | |||
servletResponse.sendRedirect(sessionExpiredURL); | |||
} else { | |||
/* | |||
* Session expired as a result of a standard http request | |||
* and we have nowhere to redirect. Reloading would likely | |||
* cause an endless loop. This can at least happen if | |||
* refreshing a resource when the session has expired. | |||
*/ | |||
response.sendError(HttpServletResponse.SC_GONE, | |||
"Session expired"); | |||
} | |||
} | |||
} catch (IOException e) { | |||
throw new ServiceException(e); | |||
} | |||
} | |||
private static final Logger getLogger() { | |||
return Logger.getLogger(VaadinServletService.class.getName()); | |||
} | |||
} |
@@ -217,6 +217,9 @@ public class FileUploadHandler implements RequestHandler { | |||
@Override | |||
public boolean handleRequest(VaadinSession session, VaadinRequest request, | |||
VaadinResponse response) throws IOException { | |||
if (!ServletPortletHelper.isFileUploadRequest(request)) { | |||
return false; | |||
} | |||
/* | |||
* URI pattern: APP/UPLOAD/[UIID]/[PID]/[NAME]/[SECKEY] See |
@@ -20,10 +20,12 @@ import java.io.IOException; | |||
import javax.servlet.http.HttpServletResponse; | |||
import com.vaadin.server.ServletPortletHelper; | |||
import com.vaadin.server.SynchronizedRequestHandler; | |||
import com.vaadin.server.VaadinRequest; | |||
import com.vaadin.server.VaadinResponse; | |||
import com.vaadin.server.VaadinSession; | |||
import com.vaadin.shared.ui.ui.UIConstants; | |||
import com.vaadin.ui.UI; | |||
/** | |||
@@ -49,6 +51,10 @@ public class HeartbeatHandler extends SynchronizedRequestHandler { | |||
@Override | |||
public boolean synchronizedHandleRequest(VaadinSession session, | |||
VaadinRequest request, VaadinResponse response) throws IOException { | |||
if (!ServletPortletHelper.isHeartbeatRequest(request)) { | |||
return false; | |||
} | |||
UI ui = session.getService().findUI(request); | |||
if (ui != null) { | |||
ui.setLastHeartbeatTimestamp(System.currentTimeMillis()); |
@@ -0,0 +1,82 @@ | |||
/* | |||
* Copyright 2000-2013 Vaadin Ltd. | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||
* use this file except in compliance with the License. You may obtain a copy of | |||
* the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||
* License for the specific language governing permissions and limitations under | |||
* the License. | |||
*/ | |||
package com.vaadin.server.communication; | |||
import java.io.BufferedWriter; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.io.OutputStreamWriter; | |||
import java.io.PrintWriter; | |||
import javax.portlet.PortletResponse; | |||
import javax.portlet.ResourceRequest; | |||
import javax.portlet.ResourceResponse; | |||
import com.vaadin.server.RequestHandler; | |||
import com.vaadin.server.VaadinPortletResponse; | |||
import com.vaadin.server.VaadinRequest; | |||
import com.vaadin.server.VaadinResponse; | |||
import com.vaadin.server.VaadinSession; | |||
/** | |||
* Request handler which provides a dummy HTML response to any resource request | |||
* with the resource id DUMMY. | |||
* | |||
* @author Vaadin Ltd | |||
* @since 7.1 | |||
*/ | |||
public class PortletDummyRequestHandler implements RequestHandler { | |||
@Override | |||
public boolean handleRequest(VaadinSession session, VaadinRequest request, | |||
VaadinResponse response) throws IOException { | |||
if (!isDummyRequest(request)) { | |||
return false; | |||
} | |||
/* | |||
* 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. | |||
*/ | |||
PortletResponse portletResponse = ((VaadinPortletResponse) response) | |||
.getPortletResponse(); | |||
if (portletResponse instanceof ResourceResponse) { | |||
((ResourceResponse) portletResponse).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(); | |||
return true; | |||
} | |||
public static boolean isDummyRequest(VaadinRequest request) { | |||
ResourceRequest resourceRequest = PortletUIInitHandler | |||
.getResourceRequest(request); | |||
if (resourceRequest == null) { | |||
return false; | |||
} | |||
return resourceRequest.getResourceID() != null | |||
&& resourceRequest.getResourceID().equals("DUMMY"); | |||
} | |||
} |
@@ -0,0 +1,63 @@ | |||
/* | |||
* Copyright 2000-2013 Vaadin Ltd. | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||
* use this file except in compliance with the License. You may obtain a copy of | |||
* the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||
* License for the specific language governing permissions and limitations under | |||
* the License. | |||
*/ | |||
package com.vaadin.server.communication; | |||
import javax.portlet.PortletRequest; | |||
import javax.portlet.ResourceRequest; | |||
import com.vaadin.server.VaadinPortletRequest; | |||
import com.vaadin.server.VaadinRequest; | |||
public class PortletUIInitHandler extends UIInitHandler { | |||
@Override | |||
protected boolean isInitRequest(VaadinRequest request) { | |||
return isUIInitRequest(request); | |||
} | |||
public static boolean isUIInitRequest(VaadinRequest request) { | |||
ResourceRequest resourceRequest = getResourceRequest(request); | |||
if (resourceRequest == null) { | |||
return false; | |||
} | |||
return UIInitHandler.BROWSER_DETAILS_PARAMETER.equals(resourceRequest | |||
.getResourceID()); | |||
} | |||
/** | |||
* Returns the {@link ResourceRequest} for the given request or null if none | |||
* could be found. | |||
* | |||
* @param request | |||
* The original request, must be a {@link VaadinPortletRequest} | |||
* @return The resource request from the request parameter or null | |||
*/ | |||
static ResourceRequest getResourceRequest(VaadinRequest request) { | |||
if (!(request instanceof VaadinPortletRequest)) { | |||
throw new IllegalArgumentException( | |||
"Request must a VaadinPortletRequest"); | |||
} | |||
PortletRequest portletRequest = ((VaadinPortletRequest) request) | |||
.getPortletRequest(); | |||
if (!(portletRequest instanceof ResourceRequest)) { | |||
return null; | |||
} | |||
return (ResourceRequest) portletRequest; | |||
} | |||
} |
@@ -28,6 +28,7 @@ import com.vaadin.annotations.StyleSheet; | |||
import com.vaadin.server.Constants; | |||
import com.vaadin.server.LegacyCommunicationManager; | |||
import com.vaadin.server.RequestHandler; | |||
import com.vaadin.server.ServletPortletHelper; | |||
import com.vaadin.server.VaadinRequest; | |||
import com.vaadin.server.VaadinResponse; | |||
import com.vaadin.server.VaadinSession; | |||
@@ -55,6 +56,9 @@ public class PublishedFileHandler implements RequestHandler { | |||
@Override | |||
public boolean handleRequest(VaadinSession session, VaadinRequest request, | |||
VaadinResponse response) throws IOException { | |||
if (!ServletPortletHelper.isPublishedFileRequest(request)) { | |||
return false; | |||
} | |||
String pathInfo = request.getPathInfo(); | |||
// + 2 to also remove beginning and ending slashes |
@@ -0,0 +1,33 @@ | |||
/* | |||
* Copyright 2000-2013 Vaadin Ltd. | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||
* use this file except in compliance with the License. You may obtain a copy of | |||
* the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||
* License for the specific language governing permissions and limitations under | |||
* the License. | |||
*/ | |||
package com.vaadin.server.communication; | |||
import com.vaadin.server.VaadinRequest; | |||
public class ServletUIInitHandler extends UIInitHandler { | |||
@Override | |||
protected boolean isInitRequest(VaadinRequest request) { | |||
return isUIInitRequest(request); | |||
} | |||
public static boolean isUIInitRequest(VaadinRequest request) { | |||
return "POST".equals(request.getMethod()) | |||
&& request | |||
.getParameter(UIInitHandler.BROWSER_DETAILS_PARAMETER) != null; | |||
} | |||
} |
@@ -22,6 +22,7 @@ import com.vaadin.server.RequestHandler; | |||
import com.vaadin.server.VaadinRequest; | |||
import com.vaadin.server.VaadinResponse; | |||
import com.vaadin.server.VaadinSession; | |||
import com.vaadin.shared.ApplicationConstants; | |||
/** | |||
* Handles a request by passing it to each registered {@link RequestHandler} in | |||
@@ -50,6 +51,13 @@ public class SessionRequestHandler implements RequestHandler { | |||
@Override | |||
public boolean handleRequest(VaadinSession session, VaadinRequest request, | |||
VaadinResponse response) throws IOException { | |||
String pathInfo = request.getPathInfo(); | |||
if (pathInfo.startsWith("/" + ApplicationConstants.APP_PATH + "/")) { | |||
// /<APP_PATH>/ is reserved for Vaadin internal use and these | |||
// requests should not be passed to session request handlers | |||
return false; | |||
} | |||
// Use a copy to avoid ConcurrentModificationException | |||
session.lock(); | |||
ArrayList<RequestHandler> requestHandlers; |
@@ -49,11 +49,18 @@ import com.vaadin.ui.UI; | |||
* @author Vaadin Ltd | |||
* @since 7.1 | |||
*/ | |||
public class UIInitHandler extends SynchronizedRequestHandler { | |||
public abstract class UIInitHandler extends SynchronizedRequestHandler { | |||
public static final String BROWSER_DETAILS_PARAMETER = "v-browserDetails"; | |||
protected abstract boolean isInitRequest(VaadinRequest request); | |||
@Override | |||
public boolean synchronizedHandleRequest(VaadinSession session, | |||
VaadinRequest request, VaadinResponse response) throws IOException { | |||
if (!isInitRequest(request)) { | |||
return false; | |||
} | |||
// NOTE! GateIn requires, for some weird reason, getOutputStream | |||
// to be used instead of getWriter() (it seems to interpret |
@@ -32,6 +32,7 @@ import com.vaadin.server.Constants; | |||
import com.vaadin.server.LegacyCommunicationManager; | |||
import com.vaadin.server.LegacyCommunicationManager.Callback; | |||
import com.vaadin.server.LegacyCommunicationManager.InvalidUIDLSecurityKeyException; | |||
import com.vaadin.server.ServletPortletHelper; | |||
import com.vaadin.server.SynchronizedRequestHandler; | |||
import com.vaadin.server.VaadinRequest; | |||
import com.vaadin.server.VaadinResponse; | |||
@@ -53,6 +54,8 @@ import com.vaadin.ui.UI; | |||
*/ | |||
public class UidlRequestHandler extends SynchronizedRequestHandler { | |||
public static final String UIDL_PATH = "UIDL/"; | |||
private Callback criticalNotifier; | |||
private ServerRpcHandler rpcHandler = new ServerRpcHandler(); | |||
@@ -64,7 +67,9 @@ public class UidlRequestHandler extends SynchronizedRequestHandler { | |||
@Override | |||
public boolean synchronizedHandleRequest(VaadinSession session, | |||
VaadinRequest request, VaadinResponse response) throws IOException { | |||
if (!ServletPortletHelper.isUIDLRequest(request)) { | |||
return false; | |||
} | |||
UI uI = session.getService().findUI(request); | |||
checkWidgetsetVersion(request); |