001/* 002 * Copyright 2002-2012 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.jsf; 018 019import java.util.Collection; 020 021import javax.faces.context.FacesContext; 022import javax.faces.event.PhaseEvent; 023import javax.faces.event.PhaseId; 024import javax.faces.event.PhaseListener; 025 026import org.springframework.beans.factory.BeanFactoryUtils; 027import org.springframework.beans.factory.ListableBeanFactory; 028import org.springframework.web.context.WebApplicationContext; 029 030/** 031 * JSF PhaseListener implementation that delegates to one or more Spring-managed 032 * PhaseListener beans coming from the Spring root WebApplicationContext. 033 * 034 * <p>Configure this listener multicaster in your {@code faces-config.xml} file 035 * as follows: 036 * 037 * <pre class="code"> 038 * <application> 039 * ... 040 * <phase-listener> 041 * org.springframework.web.jsf.DelegatingPhaseListenerMulticaster 042 * </phase-listener> 043 * ... 044 * </application></pre> 045 * 046 * The multicaster will delegate all {@code beforePhase} and {@code afterPhase} 047 * events to all target PhaseListener beans. By default, those will simply be obtained 048 * by type: All beans in the Spring root WebApplicationContext that implement the 049 * PhaseListener interface will be fetched and invoked. 050 * 051 * <p>Note: This multicaster's {@code getPhaseId()} method will always return 052 * {@code ANY_PHASE}. <b>The phase id exposed by the target listener beans 053 * will be ignored; all events will be propagated to all listeners.</b> 054 * 055 * <p>This multicaster may be subclassed to change the strategy used to obtain 056 * the listener beans, or to change the strategy used to access the ApplicationContext 057 * (normally obtained via {@link FacesContextUtils#getWebApplicationContext(FacesContext)}). 058 * 059 * @author Juergen Hoeller 060 * @author Colin Sampaleanu 061 * @since 1.2.7 062 */ 063@SuppressWarnings("serial") 064public class DelegatingPhaseListenerMulticaster implements PhaseListener { 065 066 @Override 067 public PhaseId getPhaseId() { 068 return PhaseId.ANY_PHASE; 069 } 070 071 @Override 072 public void beforePhase(PhaseEvent event) { 073 for (PhaseListener listener : getDelegates(event.getFacesContext())) { 074 listener.beforePhase(event); 075 } 076 } 077 078 @Override 079 public void afterPhase(PhaseEvent event) { 080 for (PhaseListener listener : getDelegates(event.getFacesContext())) { 081 listener.afterPhase(event); 082 } 083 } 084 085 086 /** 087 * Obtain the delegate PhaseListener beans from the Spring root WebApplicationContext. 088 * @param facesContext the current JSF context 089 * @return a Collection of PhaseListener objects 090 * @see #getBeanFactory 091 * @see org.springframework.beans.factory.ListableBeanFactory#getBeansOfType(Class) 092 */ 093 protected Collection<PhaseListener> getDelegates(FacesContext facesContext) { 094 ListableBeanFactory bf = getBeanFactory(facesContext); 095 return BeanFactoryUtils.beansOfTypeIncludingAncestors(bf, PhaseListener.class, true, false).values(); 096 } 097 098 /** 099 * Retrieve the Spring BeanFactory to delegate bean name resolution to. 100 * <p>The default implementation delegates to {@code getWebApplicationContext}. 101 * Can be overridden to provide an arbitrary ListableBeanFactory reference to 102 * resolve against; usually, this will be a full Spring ApplicationContext. 103 * @param facesContext the current JSF context 104 * @return the Spring ListableBeanFactory (never {@code null}) 105 * @see #getWebApplicationContext 106 */ 107 protected ListableBeanFactory getBeanFactory(FacesContext facesContext) { 108 return getWebApplicationContext(facesContext); 109 } 110 111 /** 112 * Retrieve the web application context to delegate bean name resolution to. 113 * <p>The default implementation delegates to FacesContextUtils. 114 * @param facesContext the current JSF context 115 * @return the Spring web application context (never {@code null}) 116 * @see FacesContextUtils#getRequiredWebApplicationContext 117 */ 118 protected WebApplicationContext getWebApplicationContext(FacesContext facesContext) { 119 return FacesContextUtils.getRequiredWebApplicationContext(facesContext); 120 } 121 122}