@Override public UIViewRoot createView(FacesContext context, String viewId) { UIViewRoot root = null; try { root = super.createView(context, viewId); } catch (RuntimeException e) { if (AjaxUtil.isAjaxRequest(context)) { // If exception was caught during our ajax request then we need to process it // and send ajax response with details about exception. CommonAjaxViewRoot.processExceptionDuringAjax(context, e); Log.log(context, e.getMessage(), e); } else { // We need to rethrow exception. throw new RuntimeException(e); } } catch (Error e) { if (AjaxUtil.isAjaxRequest(context)) { // If exception was caught during our ajax request then we need to process it // and send ajax response with details about exception. CommonAjaxViewRoot.processExceptionDuringAjax(context, e); Log.log(context, e.getMessage(), e); } else { // We need to rethrow exception. throw new Error(e); } } // If created instance of UIViewRoot does not implement our interface WrappedAjaxRoot // then we need to wrap it with our AjaxViewRoot UIViewRoot riRoot; if (null == root || root instanceof WrappedAjaxRoot) { riRoot = root; } else { riRoot = getAjaxViewRoot(root, context); } ExternalContext externalContext = context.getExternalContext(); Map<String, String> requestParameterMap = externalContext.getRequestParameterMap(); Map<String, Object> requestMap = externalContext.getRequestMap(); if (requestParameterMap.containsKey("of_sessionExpiration") && requestParameterMap.containsKey(AjaxUtil.AJAX_REQUEST_MARKER)) { if (!requestMap.containsKey(SESSION_EXPIRATION_PROCESSING)) { requestMap.put(SESSION_EXPIRATION_PROCESSING, Boolean.TRUE); String actionURL = getActionURL(context, viewId); actionURL = externalContext.encodeActionURL(actionURL); requestMap.put(LOCATION_HEADER, actionURL); } } return riRoot; }
@Override public void queueEvent(FacesEvent event) { if (AjaxUtil.isAjaxRequest(getFacesContext())) { commonAjaxViewRoot.queueEvent(event); return; } super.queueEvent(event); }
@Override public boolean getRendersChildren() { FacesContext context = FacesContext.getCurrentInstance(); // For non Ajax request, view root not render children if (!AjaxUtil.isAjaxRequest(context)) { return false; } // Ajax Request. Control all output. return true; }
private void updateSessionExpirationFlagUnderPortlets( FacesContext context, UIViewRoot root, ExternalContext externalContext, Map<String, Object> requestMap) { if (AjaxUtil.isPortletRequest(context) && externalContext.getSessionMap().containsKey(SESSION_EXPIRATION_PROCESSING) && !(requestMap.containsKey(LOCATION_HEADER))) { requestMap.put(SESSION_EXPIRATION_PROCESSING, Boolean.TRUE.toString()); addSessionExpirationFlagUnderPortlets(context, root); externalContext.getSessionMap().remove(SESSION_EXPIRATION_PROCESSING); } }
@Override public UIViewRoot restoreView(FacesContext context, String viewId) { Map<String, Object> sessionMap = context.getExternalContext().getSessionMap(); if (!sessionMap.containsKey(SESSION_SYNCHRONIZATION)) { // RequestSyncObject is required for synchronization of parallel ajax requests. // If sessionMap doesn't contain RequestSyncObject, we need to put it in. sessionMap.put(SESSION_SYNCHRONIZATION, new RequestsSyncObject()); } // Begin of synchronized block synchronized (sessionMap.get(SESSION_SYNCHRONIZATION)) { Map<String, Object> requestMap = context.getExternalContext().getRequestMap(); // RequestMap will contain SKIP_FURTHER_VIEW_HANDLERS key, only if one of our viewHandler // instances in "chain" already done it's processing. RequestsSyncObject syncObject = (RequestsSyncObject) sessionMap.get(SESSION_SYNCHRONIZATION); if (requestMap == null || !requestMap.containsKey(SKIP_FURTHER_VIEW_HANDLERS)) { while (syncObject.getAjaxRequestProcessing()) { // While we have ajax request in progress, // all new requests that comes from client should wait for finishing of previous one. try { syncObject.wait(); } catch (InterruptedException e) { // It's OK. } } } UIViewRoot viewRoot = null; try { viewRoot = super.restoreView(context, viewId); } catch (RuntimeException e) { // If exception was caught during our ajax request then we need to process it // and send ajax response with details about exception. if (AjaxUtil.isAjaxRequest(context)) { CommonAjaxViewRoot.processExceptionDuringAjax(context, e); Log.log(context, e.getMessage(), e); } else { // If current request is not our ajax request and exception was caught then we need to // rethrow exception. throw new RuntimeException(e); } } catch (Error e) { // If exception was caught during our ajax request then we need to process it // and send ajax response with details about exception. if (AjaxUtil.isAjaxRequest(context)) { CommonAjaxViewRoot.processExceptionDuringAjax(context, e); Log.log(context, e.getMessage(), e); } else { // If current request is not our ajax request and exception was caught then we need to // rethrow exception. throw new Error(e); } } if (AjaxUtil.isAjaxRequest(context)) { if (!requestMap.containsKey(SKIP_FURTHER_VIEW_HANDLERS)) { // Ajax request processing starts from here, so we need to set boolean flag // on RequestSyncObject for futher synchronization of parallel ajax requests syncObject.setAjaxRequestProcessing(true); // AjaxViewHandler's logic need to be invoked only once, // so we indicate it by putting SKIP_FURTHER_VIEW_HANDLERS attribute requestMap.put(SKIP_FURTHER_VIEW_HANDLERS, Boolean.TRUE); } } ExternalContext externalContext = context.getExternalContext(); Object httpSession = externalContext.getSession(false); boolean isSessionExpirationTesting = context .getExternalContext() .getRequestParameterMap() .containsKey(SESSION_EXPIRATION_TESTING_PARAM); // This statement checks for session expiration. It works in both client and server state // saving. if (isSessionExpirationTesting || null == httpSession || isNewSession(httpSession) || viewRoot == null) { boolean isLiferay = Environment.isLiferay(requestMap); if (!isLiferay) { if (AjaxUtil.isAjaxRequest(context) && !requestMap.containsKey(SESSION_EXPIRATION_PROCESSING)) { // If session expired, we need to set request scoped parameter, // this will indicate session expiration processing. requestMap.put(SESSION_EXPIRATION_PROCESSING, Boolean.TRUE); if (AjaxUtil.isPortletRequest(context)) { // In portlet environment we need to set session scoped parameter that indicate // session expiration processing // because in portlet for one user request, we have ActionRequest and RenderRequest on // a server. // Both these requests have their own request maps. sessionMap.put(SESSION_EXPIRATION_PROCESSING, Boolean.TRUE); } if (!AjaxUtil.isPortletRequest(context)) { // After session expired, we need to send to the client redirect location url // So, here we encode redirect url for current view and put it into requestMap for // futher processing. String actionURL = getActionURL(context, viewId); actionURL = externalContext.encodeActionURL(actionURL); requestMap.put(LOCATION_HEADER, actionURL); } return null; } } else { // If we work in LifeRay environment, we need only to set session-scoped parameter, that // current session was expired and we will process it accordingly. if (AjaxUtil.isAjaxRequest(context)) { sessionMap.put(SESSION_EXPIRATION_PROCESSING, Boolean.TRUE); } } } return viewRoot; } }
private void processSessionExpirationUnderPortletsMyFaces( FacesContext context, UIViewRoot root, ExternalContext externalContext, Object session) { Object requestObject = context.getExternalContext().getRequest(); HttpServletRequest catalinaServletRequest = null; try { Class jbossRenderRequestClass = Class.forName("org.jboss.portlet.JBossRenderRequest"); Class abstractRequestContextClass = Class.forName("org.jboss.portal.portlet.impl.spi.AbstractRequestContext"); Class requestObjectClass = requestObject.getClass(); if (jbossRenderRequestClass.isAssignableFrom(requestObjectClass)) { Field requestContextField = requestObject .getClass() .getSuperclass() .getSuperclass() .getDeclaredField("requestContext"); requestContextField.setAccessible(true); Object requestContext = requestContextField.get(requestObject); Class requestContextClass = requestContext.getClass(); if (abstractRequestContextClass.isAssignableFrom(requestContextClass)) { Field reqField = requestContextClass.getDeclaredField("req"); reqField.setAccessible(true); Object req = reqField.get(requestContext); if (req instanceof HttpServletRequest) { catalinaServletRequest = (HttpServletRequest) req; } } } } catch (ClassNotFoundException e) { externalContext.log(e.getMessage()); } catch (NoSuchFieldException e) { externalContext.log(e.getMessage()); } catch (IllegalAccessException e) { externalContext.log(e.getMessage()); } if (AjaxUtil.isPortletRenderRequest(context) && !AjaxUtil.isAjaxRequest(context) && catalinaServletRequest != null && catalinaServletRequest.getParameterMap().size() > 0) { if (isNewSession(session)) { addAjaxRequestMarkerUnderPortlets(context, root); addSessionExpirationFlagUnderPortlets(context, root); } } if (Environment.isLiferay(context.getExternalContext().getRequestMap())) { if (context .getExternalContext() .getSessionMap() .containsKey(AjaxViewHandler.SESSION_EXPIRATION_PROCESSING)) { addAjaxRequestMarkerUnderPortlets(context, root); addSessionExpirationFlagUnderPortlets(context, root); context .getExternalContext() .getSessionMap() .remove(AjaxViewHandler.SESSION_EXPIRATION_PROCESSING); } } }
@Override public void renderView(FacesContext context, UIViewRoot root) throws IOException, FacesException { Components.runScheduledActions(); if (!context.getResponseComplete()) { ExternalContext externalContext = context.getExternalContext(); Object session = externalContext.getSession(false); Map<String, Object> requestMap = externalContext.getRequestMap(); if (externalContext.getSessionMap().containsKey(ERROR_OCCURRED_UNDER_PORTLETS)) { processExceptionUnderPortlets(context); return; } if (AjaxUtil.isPortletRequest(context) && Environment.isMyFaces() && isNewSession(externalContext.getSession(false))) { processSessionExpirationUnderPortletsMyFaces(context, root, externalContext, session); } if (AjaxUtil.isPortletRequest(context) && Environment.isRI() && isNewSession(externalContext.getSession(false))) { processSessionExpirationUnderPortletsRI(context, root, externalContext); } boolean ajaxRequest = AjaxUtil.isAjaxRequest(context); if (!ajaxRequest && !AjaxUtil.isAjax4jsfRequest()) ValidationSupportResponseWriter.resetBubbleIndex(context); if (ajaxRequest) { updateSessionExpirationFlagUnderPortlets(context, root, externalContext, requestMap); try { // HACK for MyFaces ( <f:view> tag not call renderers ) // ServletResponse response = (ServletResponse) context // .getExternalContext().getResponse(); Object response = externalContext.getResponse(); if (!AjaxUtil.isPortletRequest(context)) { try { response.getClass().getDeclaredMethod("resetResponse").invoke(response); // response.reset(); } catch (Exception e) { // Do nothing - we will use directly and reset // wrapper } } if (requestMap.containsKey(SESSION_EXPIRATION_PROCESSING)) { super.renderView(context, root); // This is done for MyFaces use-case, because MyFaces doesn't call rendering methods for // ViewRoot if (!Environment.isRI()) { root.encodeChildren(context); } Map<String, Object> sessionMap = context.getExternalContext().getSessionMap(); if (sessionMap != null && !sessionMap.containsKey(SESSION_SCOPED_PARAMETER)) { sessionMap.put(SESSION_SCOPED_PARAMETER, Boolean.TRUE.toString()); } return; } if (Environment.isFacelets(context)) { super.renderView(context, root); } else { root.encodeBegin(context); if (root.getRendersChildren()) { root.encodeChildren(context); } root.encodeEnd(context); } } catch (RuntimeException e) { CommonAjaxViewRoot.processExceptionDuringAjax(context, e); externalContext.log(e.getMessage(), e); } catch (Error e) { CommonAjaxViewRoot.processExceptionDuringAjax(context, e); externalContext.log(e.getMessage(), e); } } else { super.renderView(context, root); Map<String, Object> sessionMap = context.getExternalContext().getSessionMap(); if (sessionMap != null && !sessionMap.containsKey(SESSION_SCOPED_PARAMETER)) { sessionMap.put(SESSION_SCOPED_PARAMETER, Boolean.TRUE.toString()); } if (AjaxUtil.isAjax4jsfRequest()) { Resources.processHeadResources(context); } } } }