You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2009/11/24 02:24:45 UTC
svn commit: r883564 - in
/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces: config/ webapp/
Author: lu4242
Date: Tue Nov 24 01:24:37 2009
New Revision: 883564
URL: http://svn.apache.org/viewvc?rev=883564&view=rev
Log:
MYFACES-2396 @PreDestroy method of Bean in CustomScope not invoked (Thanks to Jakob Korherr for this patch)
Added:
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/ManagedBeanDestroyer.java
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/ManagedBeanDestroyerListener.java
Removed:
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/AbstractMyFacesListener.java
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/MyFacesHttpSessionAttributeListener.java
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/MyFacesHttpSessionListener.java
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/MyFacesServletContextListener.java
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/MyFacesServletRequestListener.java
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/MyfacesServletRequestAttributeListener.java
Modified:
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/StartupServletContextListener.java
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java?rev=883564&r1=883563&r2=883564&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java Tue Nov 24 01:24:37 2009
@@ -64,6 +64,8 @@
import javax.faces.event.ActionListener;
import javax.faces.event.PhaseListener;
import javax.faces.event.PostConstructApplicationEvent;
+import javax.faces.event.PreDestroyCustomScopeEvent;
+import javax.faces.event.PreDestroyViewMapEvent;
import javax.faces.event.SystemEvent;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
@@ -1723,6 +1725,11 @@
runtimeConfig.setVariableResolverChainHead(getApplicationObject(VariableResolver.class,
dispenser.getVariableResolverIterator(),
new VariableResolverImpl()));
+
+ // configure ManagedBeanDestroyer to listen to PreDestroyCustomScopeEvent and PreDestroyViewMapEvent
+ ManagedBeanDestroyer mbDestroyer = new ManagedBeanDestroyer();
+ application.subscribeToEvent(PreDestroyCustomScopeEvent.class, mbDestroyer);
+ application.subscribeToEvent(PreDestroyViewMapEvent.class, mbDestroyer);
}
/**
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/ManagedBeanDestroyer.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/ManagedBeanDestroyer.java?rev=883564&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/ManagedBeanDestroyer.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/config/ManagedBeanDestroyer.java Tue Nov 24 01:24:37 2009
@@ -0,0 +1,176 @@
+/*
+ * 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.myfaces.config;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.event.PreDestroyCustomScopeEvent;
+import javax.faces.event.PreDestroyViewMapEvent;
+import javax.faces.event.ScopeContext;
+import javax.faces.event.SystemEvent;
+import javax.faces.event.SystemEventListener;
+
+import org.apache.myfaces.config.annotation.LifecycleProvider;
+import org.apache.myfaces.config.annotation.LifecycleProviderFactory;
+
+/**
+ * Destroyes managed beans with the current LifecycleProvider.
+ * This guarantees the invocation of the @PreDestroy methods.
+ * @author Jakob Korherr (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ * @since 2.0
+ */
+public class ManagedBeanDestroyer implements SystemEventListener
+{
+
+ private static Logger log = Logger.getLogger(ManagedBeanDestroyer.class.getName());
+
+ private RuntimeConfig runtimeConfig;
+
+ public void setRuntimeConfig(RuntimeConfig runtimeConfig)
+ {
+ this.runtimeConfig = runtimeConfig;
+ }
+
+ public RuntimeConfig getRuntimeConfig()
+ {
+ if (runtimeConfig == null)
+ {
+ ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
+ runtimeConfig = RuntimeConfig.getCurrentInstance(externalContext);
+ }
+ return runtimeConfig;
+ }
+
+ public boolean isListenerForSource(Object source)
+ {
+ // source of PreDestroyCustomScopeEvent is ScopeContext
+ // and source of PreDestroyViewMapEvent is UIViewRoot
+ return (source instanceof ScopeContext) || (source instanceof UIViewRoot);
+ }
+
+
+ /**
+ * Listens to PreDestroyCustomScopeEvent and PreDestroyViewMapEvent
+ * and invokes destroy() for every managed bean in the associated scope.
+ */
+ public void processEvent(SystemEvent event)
+ {
+ Map<String, Object> scope = null;
+
+ if (event instanceof PreDestroyViewMapEvent)
+ {
+ UIViewRoot viewRoot = (UIViewRoot) ((PreDestroyViewMapEvent) event).getComponent();
+ scope = viewRoot.getViewMap(false);
+ if (scope == null)
+ {
+ // view map does not exist --> nothing to destroy
+ return;
+ }
+ }
+ else if (event instanceof PreDestroyCustomScopeEvent)
+ {
+ ScopeContext scopeContext = ((PreDestroyCustomScopeEvent) event).getContext();
+ scope = scopeContext.getScope();
+ }
+ else
+ {
+ // wrong event
+ return;
+ }
+
+ LifecycleProvider provider = getCurrentLifecycleProvider();
+ for (String key : scope.keySet())
+ {
+ Object value = scope.get(key);
+ this.destroy(key, value, provider);
+ }
+ }
+
+ /**
+ * Checks if the given managed bean exists in the RuntimeConfig.
+ * @param name
+ * @return
+ */
+ public boolean isManagedBean(String name)
+ {
+ return getRuntimeConfig().getManagedBean(name) != null;
+ }
+
+ /**
+ * Destroys the given managed bean with the current LifecycleProvider.
+ * @param name
+ * @param instance
+ */
+ public void destroy(String name, Object instance)
+ {
+ destroy(name, instance, getCurrentLifecycleProvider());
+ }
+
+ /**
+ * Destroys the given managed bean with the given LifecycleProvider
+ * @param name
+ * @param instance
+ * @param provider
+ */
+ public void destroy(String name, Object instance, LifecycleProvider provider)
+ {
+ if (isManagedBean(name)) {
+ if (provider == null)
+ {
+ provider = getCurrentLifecycleProvider();
+ }
+ try
+ {
+ provider.destroyInstance(instance);
+ }
+ catch (IllegalAccessException e)
+ {
+ log.log(Level.SEVERE, "Could not access @PreDestroy method of managed bean " + name, e);
+ }
+ catch (InvocationTargetException e)
+ {
+ log.log(Level.SEVERE, "An Exception occured while invoking " +
+ "@PreDestroy method of managed bean " + name, e);
+ }
+ }
+ }
+
+ /**
+ * Retrieves the current LifecycleProvider from the LifecycleProviderFactory
+ * @return
+ */
+ public LifecycleProvider getCurrentLifecycleProvider()
+ {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ if (facesContext == null)
+ {
+ return LifecycleProviderFactory.getLifecycleProviderFactory().getLifecycleProvider(null);
+ }
+ ExternalContext externalContext = facesContext.getExternalContext();
+ return LifecycleProviderFactory.getLifecycleProviderFactory().getLifecycleProvider(externalContext);
+ }
+
+}
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/ManagedBeanDestroyerListener.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/ManagedBeanDestroyerListener.java?rev=883564&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/ManagedBeanDestroyerListener.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/ManagedBeanDestroyerListener.java Tue Nov 24 01:24:37 2009
@@ -0,0 +1,200 @@
+/*
+ * 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.myfaces.webapp;
+
+import java.util.Enumeration;
+
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextAttributeEvent;
+import javax.servlet.ServletContextAttributeListener;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletRequestAttributeEvent;
+import javax.servlet.ServletRequestAttributeListener;
+import javax.servlet.ServletRequestEvent;
+import javax.servlet.ServletRequestListener;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionListener;
+
+import org.apache.myfaces.config.ManagedBeanDestroyer;
+import org.apache.myfaces.config.RuntimeConfig;
+import org.apache.myfaces.config.annotation.LifecycleProvider;
+
+/**
+ * Listens to
+ * - removing, replacing of attributes in context, session and request
+ * - destroying of context, session and request
+ * for the ManagedBeanDestroyer to assure right destruction of managed beans in those scopes.
+ *
+ * This listener is not registered in a tld or web.xml, but will be called by StartupServletContextListener.
+ *
+ * @author Jakob Korherr (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ * @since 2.0
+ */
+public class ManagedBeanDestroyerListener implements
+ HttpSessionAttributeListener, HttpSessionListener,
+ ServletContextListener, ServletContextAttributeListener,
+ ServletRequestListener, ServletRequestAttributeListener
+{
+
+ private ManagedBeanDestroyer destroyer = new ManagedBeanDestroyer();
+
+ /* Session related methods */
+
+ public void attributeAdded(HttpSessionBindingEvent event)
+ {
+ // noop
+ }
+
+ public void attributeRemoved(HttpSessionBindingEvent event)
+ {
+ destroyer.destroy(event.getName(), event.getValue());
+ }
+
+ public void attributeReplaced(HttpSessionBindingEvent event)
+ {
+ destroyer.destroy(event.getName(), event.getValue());
+ }
+
+ public void sessionCreated(HttpSessionEvent event)
+ {
+ // noop
+ }
+
+ @SuppressWarnings("unchecked")
+ public void sessionDestroyed(HttpSessionEvent event)
+ {
+ HttpSession session = event.getSession();
+ Enumeration<String> attributes = session.getAttributeNames();
+ if (!attributes.hasMoreElements())
+ {
+ // nothing to do
+ return;
+ }
+ // optimization: provide the LifecycleProvider, because there could be a lot of elements
+ LifecycleProvider provider = destroyer.getCurrentLifecycleProvider();
+
+ while (attributes.hasMoreElements())
+ {
+ String name = attributes.nextElement();
+ Object value = session.getAttribute(name);
+ destroyer.destroy(name, value, provider);
+ }
+ }
+
+ /* Context related methods */
+
+ public void attributeAdded(ServletContextAttributeEvent event)
+ {
+ // noop
+ }
+
+ public void attributeRemoved(ServletContextAttributeEvent event)
+ {
+ destroyer.destroy(event.getName(), event.getValue());
+ }
+
+ public void attributeReplaced(ServletContextAttributeEvent event)
+ {
+ destroyer.destroy(event.getName(), event.getValue());
+ }
+
+ public void contextInitialized(ServletContextEvent event)
+ {
+ // set the RuntimeConfig of ManagedBeanDestroyer, because
+ // in requestDestroyed, contextDestroyed FacesContext.getCurrentInstance() returns
+ // null and so we wouln't get the RuntimeConfig.
+ ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
+ RuntimeConfig config = RuntimeConfig.getCurrentInstance(externalContext);
+ destroyer.setRuntimeConfig(config);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void contextDestroyed(ServletContextEvent event)
+ {
+ ServletContext ctx = event.getServletContext();
+ Enumeration<String> attributes = ctx.getAttributeNames();
+ if (!attributes.hasMoreElements())
+ {
+ // nothing to do
+ return;
+ }
+ // optimization: provide the LifecycleProvider, because there could be a lot of elements
+ LifecycleProvider provider = destroyer.getCurrentLifecycleProvider();
+
+ while (attributes.hasMoreElements())
+ {
+ String name = attributes.nextElement();
+ Object value = ctx.getAttribute(name);
+ destroyer.destroy(name, value, provider);
+ }
+
+ }
+
+ /* Request related methods */
+
+ public void attributeAdded(ServletRequestAttributeEvent event)
+ {
+ // noop
+ }
+
+ public void attributeRemoved(ServletRequestAttributeEvent event)
+ {
+ destroyer.destroy(event.getName(), event.getValue());
+ }
+
+ public void attributeReplaced(ServletRequestAttributeEvent event)
+ {
+ destroyer.destroy(event.getName(), event.getValue());
+ }
+
+ public void requestInitialized(ServletRequestEvent event)
+ {
+ // noop
+ }
+
+ @SuppressWarnings("unchecked")
+ public void requestDestroyed(ServletRequestEvent event)
+ {
+ ServletRequest request = event.getServletRequest();
+ Enumeration<String> attributes = request.getAttributeNames();
+ if (!attributes.hasMoreElements())
+ {
+ // nothing to do
+ return;
+ }
+ // optimization: provide the LifecycleProvider, because there could be a lot of elements
+ LifecycleProvider provider = destroyer.getCurrentLifecycleProvider();
+
+ while (attributes.hasMoreElements())
+ {
+ String name = attributes.nextElement();
+ Object value = request.getAttribute(name);
+ destroyer.destroy(name, value, provider);
+ }
+ }
+
+}
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/StartupServletContextListener.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/StartupServletContextListener.java?rev=883564&r1=883563&r2=883564&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/StartupServletContextListener.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/StartupServletContextListener.java Tue Nov 24 01:24:37 2009
@@ -18,16 +18,24 @@
*/
package org.apache.myfaces.webapp;
-import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.FactoryFinder;
import javax.servlet.ServletContext;
+import javax.servlet.ServletContextAttributeEvent;
+import javax.servlet.ServletContextAttributeListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
+import javax.servlet.ServletRequestAttributeEvent;
+import javax.servlet.ServletRequestAttributeListener;
+import javax.servlet.ServletRequestEvent;
+import javax.servlet.ServletRequestListener;
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionListener;
-import org.apache.myfaces.config.ManagedBeanBuilder;
import org.apache.myfaces.shared_impl.util.ClassUtils;
import org.apache.myfaces.util.ContainerUtils;
@@ -43,10 +51,16 @@
* generated. Very old versions of MyFaces Core do not register the listener in the .tld file, so those also need a
* manual entry in web.xml. However all versions since at least 1.1.2 have this entry in the tld.
*
+ * This listener also delegates all session, request and context events to ManagedBeanDestroyer.
+ * Because of that we only need to register one listener in the tld.
+ *
* @author Manfred Geiler (latest modification by $Author$)
* @version $Revision$ $Date$
*/
-public class StartupServletContextListener extends AbstractMyFacesListener implements ServletContextListener
+public class StartupServletContextListener implements ServletContextListener,
+ HttpSessionAttributeListener, HttpSessionListener,
+ ServletRequestListener, ServletRequestAttributeListener,
+ ServletContextAttributeListener
{
static final String FACES_INIT_DONE = StartupServletContextListener.class.getName() + ".FACES_INIT_DONE";
/*comma delimited list of plugin classes which can be hooked into myfaces*/
@@ -62,6 +76,7 @@
private FacesInitializer _facesInitializer;
private ServletContext _servletContext;
+ private ManagedBeanDestroyerListener _detroyerListener = new ManagedBeanDestroyerListener();
/**
@@ -88,7 +103,7 @@
//for now the initializers have to be stateless to
//so that we do not have to enforce that the initializer
//must be serializable
- Class pluginClass = ClassUtils.getContextClassLoader().loadClass(plugin);
+ Class<?> pluginClass = ClassUtils.getContextClassLoader().loadClass(plugin);
StartupListener initializer = (StartupListener) pluginClass.newInstance();
switch(operation) {
@@ -140,6 +155,9 @@
{
log.info("MyFaces already initialized");
}
+
+ // call contextInitialized on ManagedBeanDestroyerListener
+ _detroyerListener.contextInitialized(event);
}
protected FacesInitializer getFacesInitializer()
@@ -179,7 +197,9 @@
public void contextDestroyed(ServletContextEvent event)
{
- doPredestroy(event);
+ dispatchInitializationEvent(event, FACES_INIT_PHASE_PREDESTROY);
+ // call contextDestroyed on ManagedBeanDestroyerListener to destroy the attributes
+ _detroyerListener.contextDestroyed(event);
if (_facesInitializer != null && _servletContext != null)
{
@@ -190,20 +210,77 @@
_servletContext = null;
}
+
+ /* the following methods are needed to serve ManagedBeanDestroyerListener */
+ /* Session related methods */
+
+ public void attributeAdded(HttpSessionBindingEvent event)
+ {
+ _detroyerListener.attributeAdded(event);
+ }
- @SuppressWarnings("unchecked")
- private void doPredestroy(ServletContextEvent event)
+ public void attributeRemoved(HttpSessionBindingEvent event)
{
- ServletContext ctx = event.getServletContext();
- dispatchInitializationEvent(event, FACES_INIT_PHASE_PREDESTROY);
+ _detroyerListener.attributeRemoved(event);
+ }
- Enumeration<String> attributes = ctx.getAttributeNames();
+ public void attributeReplaced(HttpSessionBindingEvent event)
+ {
+ _detroyerListener.attributeReplaced(event);
+ }
- while (attributes.hasMoreElements())
- {
- String name = attributes.nextElement();
- Object value = ctx.getAttribute(name);
- doPreDestroy(value, name, ManagedBeanBuilder.APPLICATION);
- }
+ public void sessionCreated(HttpSessionEvent event)
+ {
+ _detroyerListener.sessionCreated(event);
+ }
+
+ public void sessionDestroyed(HttpSessionEvent event)
+ {
+ _detroyerListener.sessionDestroyed(event);
}
+
+ /* Context related methods */
+
+ public void attributeAdded(ServletContextAttributeEvent event)
+ {
+ _detroyerListener.attributeAdded(event);
+ }
+
+ public void attributeRemoved(ServletContextAttributeEvent event)
+ {
+ _detroyerListener.attributeRemoved(event);
+ }
+
+ public void attributeReplaced(ServletContextAttributeEvent event)
+ {
+ _detroyerListener.attributeReplaced(event);
+ }
+
+ /* Request related methods */
+
+ public void attributeAdded(ServletRequestAttributeEvent event)
+ {
+ _detroyerListener.attributeAdded(event);
+ }
+
+ public void attributeRemoved(ServletRequestAttributeEvent event)
+ {
+ _detroyerListener.attributeRemoved(event);
+ }
+
+ public void attributeReplaced(ServletRequestAttributeEvent event)
+ {
+ _detroyerListener.attributeReplaced(event);
+ }
+
+ public void requestInitialized(ServletRequestEvent event)
+ {
+ _detroyerListener.requestInitialized(event);
+ }
+
+ public void requestDestroyed(ServletRequestEvent event)
+ {
+ _detroyerListener.requestDestroyed(event);
+ }
+
}