/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.deltaspike.jsf.impl.listener.request; import org.apache.deltaspike.core.api.provider.BeanProvider; import org.apache.deltaspike.core.util.ExceptionUtils; import org.apache.deltaspike.jsf.impl.scope.window.ClientWindowAdapter; import org.apache.deltaspike.jsf.spi.scope.window.ClientWindow; import org.apache.deltaspike.jsf.spi.scope.window.ClientWindowConfig; import javax.faces.context.FacesContext; import javax.faces.lifecycle.Lifecycle; import javax.faces.lifecycle.LifecycleWrapper; import java.lang.reflect.Field; import javax.faces.FacesException; //ATTENTION: don't rename/move this class as long as we need the workaround in impl-ee6 //(further details are available at: DELTASPIKE-655 and DELTASPIKE-659) @SuppressWarnings("UnusedDeclaration") public class JsfClientWindowAwareLifecycleWrapper extends LifecycleWrapper { private final Lifecycle wrapped; private volatile Boolean initialized; private ClientWindowConfig clientWindowConfig; public JsfClientWindowAwareLifecycleWrapper(Lifecycle wrapped) { this.wrapped = wrapped; } @Override public Lifecycle getWrapped() { return wrapped; } @Override public void attachWindow(FacesContext facesContext) { lazyInit(); boolean delegateWindowHandling = ClientWindowConfig.ClientWindowRenderMode.DELEGATED.equals( clientWindowConfig.getClientWindowRenderMode(facesContext)); if (delegateWindowHandling) { try { //the first wrapper is always DeltaSpikeLifecycleWrapper which can't extend from LifecycleWrapper Lifecycle externalWrapper = ((DeltaSpikeLifecycleWrapper)this.wrapped).getWrapped(); delegateAttachWindow(facesContext, externalWrapper); } catch (Exception e) { try { attachWindowOnUnwrappedInstance(facesContext, this.wrapped); } catch (Exception e1) { throw ExceptionUtils.throwAsRuntimeException(e); } } } else { ClientWindow clientWindow = BeanProvider.getContextualReference(ClientWindow.class); //trigger init - might lead to a redirect -> response-complete String windowId = clientWindow.getWindowId(facesContext); if (!facesContext.getResponseComplete() && !"default".equals(windowId)) { facesContext.getExternalContext().setClientWindow(new ClientWindowAdapter(clientWindow)); } } } private void attachWindowOnUnwrappedInstance(FacesContext facesContext, Lifecycle wrapped) throws Exception { Lifecycle wrappedLifecycle = null; if (wrapped instanceof LifecycleWrapper) { wrappedLifecycle = ((LifecycleWrapper)wrapped).getWrapped(); } //needed to support some libs which don't use LifecycleWrapper, because it's a jsf 2.2+ api if (wrappedLifecycle == null) { for (Field field : wrapped.getClass().getDeclaredFields()) { if (Lifecycle.class.isAssignableFrom(field.getType())) { if (!field.isAccessible()) { field.setAccessible(true); } wrappedLifecycle = (Lifecycle)field.get(wrapped); break; } } } if (wrappedLifecycle != null) { try { delegateAttachWindow(facesContext, wrappedLifecycle); } catch (Exception e) { attachWindowOnUnwrappedInstance(facesContext, wrappedLifecycle); } } } private static void delegateAttachWindow(FacesContext facesContext, Lifecycle lifecycle) throws Exception { //if there is an external wrapper (e.g. in case of other libs), we have to check //the version of javax.faces.lifecycle.Lifecycle (>= or < v2.2) //without the check and an old lib (in the classpath) #attachWindow would get ignored without exception if (lifecycle instanceof LifecycleWrapper /*autom. provides #attachWindow*/ || lifecycle.getClass().getDeclaredMethod("attachWindow", FacesContext.class) != null) { lifecycle.attachWindow(facesContext); } } @Override public void render(FacesContext facesContext) throws FacesException { lazyInit(); // prevent jfwid rendering boolean delegateWindowHandling = ClientWindowConfig.ClientWindowRenderMode.DELEGATED.equals( clientWindowConfig.getClientWindowRenderMode(facesContext)); if (!delegateWindowHandling && facesContext.getExternalContext().getClientWindow() != null) { facesContext.getExternalContext().getClientWindow().disableClientWindowRenderMode(facesContext); } super.render(facesContext); } private void lazyInit() { if (this.initialized == null) { init(); } } private synchronized void init() { // switch into paranoia mode if (this.initialized == null) { this.clientWindowConfig = BeanProvider.getContextualReference(ClientWindowConfig.class); this.initialized = true; } } }