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 2013/08/12 01:54:53 UTC
svn commit: r1513021 [3/3] - in /myfaces/core/trunk:
api/src/main/java/javax/faces/component/
impl/src/main/java/org/apache/myfaces/cdi/
impl/src/main/java/org/apache/myfaces/cdi/impl/
impl/src/main/java/org/apache/myfaces/cdi/util/ impl/src/main/java/...
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultViewScopeProviderFactory.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultViewScopeProviderFactory.java?rev=1513021&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultViewScopeProviderFactory.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultViewScopeProviderFactory.java Sun Aug 11 23:54:52 2013
@@ -0,0 +1,69 @@
+/*
+ * 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.spi.impl;
+
+import javax.faces.context.ExternalContext;
+import org.apache.myfaces.shared.util.ClassUtils;
+import org.apache.myfaces.spi.ViewScopeProvider;
+import org.apache.myfaces.spi.ViewScopeProviderFactory;
+import org.apache.myfaces.util.ExternalSpecifications;
+import org.apache.myfaces.view.impl.DefaultViewScopeHandler;
+
+/**
+ *
+ * @author Leonardo Uribe
+ */
+public class DefaultViewScopeProviderFactory extends ViewScopeProviderFactory
+{
+
+ public static final String VIEW_SCOPE_HANDLER = ViewScopeProvider.class.getName();
+ public static final String VIEW_SCOPE_HANDLER_INSTANCE_KEY = VIEW_SCOPE_HANDLER + ".INSTANCE";
+
+ @Override
+ public ViewScopeProvider getViewScopeHandler(ExternalContext externalContext)
+ {
+ // check for cached instance
+ ViewScopeProvider returnValue = (ViewScopeProvider)
+ externalContext.getApplicationMap().get(VIEW_SCOPE_HANDLER_INSTANCE_KEY);
+
+ if (returnValue == null)
+ {
+ if (ExternalSpecifications.isCDIAvailable(externalContext))
+ {
+ returnValue = (ViewScopeProvider) ClassUtils.newInstance(
+ "org.apache.myfaces.cdi.impl.CDIManagedBeanHandlerImpl");
+ //CDIManagedBeanHandler.getInstance(externalContext);
+ }
+ else
+ {
+ returnValue = new DefaultViewScopeHandler();
+ }
+ // cache the result on the ApplicationMap
+ externalContext.getApplicationMap().put(VIEW_SCOPE_HANDLER_INSTANCE_KEY, returnValue);
+ }
+
+ return returnValue;
+ }
+
+ @Override
+ public void setViewScopeHandler(ExternalContext externalContext, ViewScopeProvider viewScopeHandler)
+ {
+ externalContext.getApplicationMap().put(VIEW_SCOPE_HANDLER_INSTANCE_KEY, viewScopeHandler);
+ }
+}
Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/spi/impl/DefaultViewScopeProviderFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/util/ExternalSpecifications.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/util/ExternalSpecifications.java?rev=1513021&r1=1513020&r2=1513021&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/util/ExternalSpecifications.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/util/ExternalSpecifications.java Sun Aug 11 23:54:52 2013
@@ -22,6 +22,8 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import javax.el.ELContext;
+import javax.faces.context.ExternalContext;
+import org.apache.myfaces.webapp.AbstractFacesInitializer;
/**
* <p>
@@ -42,6 +44,7 @@ public final class ExternalSpecification
private static volatile Boolean beanValidationAvailable;
private static volatile Boolean unifiedELAvailable;
+ private static volatile Boolean cdiAvailable;
/**
* This method determines if Bean Validation is present.
@@ -124,6 +127,41 @@ public final class ExternalSpecification
}
return unifiedELAvailable;
}
+
+ public static boolean isCDIAvailable(ExternalContext externalContext)
+ {
+ if (cdiAvailable == null)
+ {
+ try
+ {
+ cdiAvailable = Class.forName("javax.enterprise.inject.spi.BeanManager") != null;
+ }
+ catch (Throwable t)
+ {
+ //log.log(Level.FINE, "Error loading class (could be normal)", t);
+ cdiAvailable = false;
+ }
+
+ if (cdiAvailable)
+ {
+ cdiAvailable = externalContext.getApplicationMap().containsKey(
+ AbstractFacesInitializer.CDI_BEAN_MANAGER_INSTANCE);
+ }
+
+ log.info("MyFaces CDI support " + (cdiAvailable ? "enabled" : "disabled"));
+
+ return cdiAvailable;
+ }
+ else
+ {
+ if (Boolean.TRUE.equals(cdiAvailable))
+ {
+ return externalContext.getApplicationMap().containsKey(
+ AbstractFacesInitializer.CDI_BEAN_MANAGER_INSTANCE);
+ }
+ return cdiAvailable;
+ }
+ }
/**
* this class should not be instantiated.
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/ViewScopeProxyMap.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/ViewScopeProxyMap.java?rev=1513021&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/ViewScopeProxyMap.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/ViewScopeProxyMap.java Sun Aug 11 23:54:52 2013
@@ -0,0 +1,175 @@
+/*
+ * 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.view;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import javax.faces.component.StateHolder;
+import javax.faces.context.FacesContext;
+import javax.faces.event.PreDestroyViewMapEvent;
+import org.apache.myfaces.spi.ViewScopeProvider;
+import org.apache.myfaces.spi.ViewScopeProviderFactory;
+
+/**
+ * This wrapper has these objectives:
+ *
+ * - Isolate the part that needs to be saved with the view (viewScopeId) from
+ * the part that should remain into session (bean map). This class will be
+ * serialized when UIViewRoot.saveState() is called.
+ * - Decouple the way how the view scope map is stored. For example, in
+ * CDI view scope a session scope bean is used, and in default view scope
+ * the same session map is used but using a prefix.
+ *
+ * @author Leonardo Uribe
+ */
+public class ViewScopeProxyMap implements Map<String, Object>, StateHolder
+{
+ private String _viewScopeId;
+
+ private transient Map<String, Object> _delegate;
+
+ public ViewScopeProxyMap()
+ {
+ }
+
+
+ public String getViewScopeId()
+ {
+ return _viewScopeId;
+ }
+
+ public void forceCreateWrappedMap(FacesContext facesContext)
+ {
+ getWrapped();
+ }
+
+ public Map<String, Object> getWrapped()
+ {
+ if (_delegate == null)
+ {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+
+ ViewScopeProviderFactory factory = ViewScopeProviderFactory.getViewScopeHandlerFactory(
+ facesContext.getExternalContext());
+
+ ViewScopeProvider handler = factory.getViewScopeHandler(facesContext.getExternalContext());
+
+ if (_viewScopeId == null)
+ {
+ _viewScopeId = handler.generateViewScopeId(facesContext);
+ _delegate = handler.createViewScopeMap(facesContext, _viewScopeId);
+ }
+ else
+ {
+ _delegate = handler.restoreViewScopeMap(facesContext, _viewScopeId);
+ }
+ }
+ return _delegate;
+ }
+
+ public int size()
+ {
+ return getWrapped().size();
+ }
+
+ public boolean isEmpty()
+ {
+ return getWrapped().isEmpty();
+ }
+
+ public boolean containsKey(Object key)
+ {
+ return getWrapped().containsKey(key);
+ }
+
+ public boolean containsValue(Object value)
+ {
+ return getWrapped().containsValue(value);
+ }
+
+ public Object get(Object key)
+ {
+ return getWrapped().get(key);
+ }
+
+ public Object put(String key, Object value)
+ {
+ return getWrapped().put(key, value);
+ }
+
+ public Object remove(Object key)
+ {
+ return getWrapped().remove(key);
+ }
+
+ public void putAll(Map<? extends String, ? extends Object> m)
+ {
+ getWrapped().putAll(m);
+ }
+
+ public void clear()
+ {
+ /*
+ * The returned Map must be implemented such that calling clear() on the Map causes
+ * Application.publishEvent(java.lang.Class, java.lang.Object) to be called, passing
+ * ViewMapDestroyedEvent.class as the first argument and this UIViewRoot instance as the second argument.
+ */
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ facesContext.getApplication().publishEvent(facesContext,
+ PreDestroyViewMapEvent.class, facesContext.getViewRoot());
+
+ getWrapped().clear();
+ }
+
+ public Set<String> keySet()
+ {
+ return getWrapped().keySet();
+ }
+
+ public Collection<Object> values()
+ {
+ return getWrapped().values();
+ }
+
+ public Set<Entry<String, Object>> entrySet()
+ {
+ return getWrapped().entrySet();
+ }
+
+ public void restoreState(FacesContext context, Object state)
+ {
+ _viewScopeId = (String) state;
+ }
+
+ public Object saveState(FacesContext context)
+ {
+ return _viewScopeId;
+ }
+
+ public boolean isTransient()
+ {
+ return false;
+ }
+
+ public void setTransient(boolean newTransientValue)
+ {
+ }
+
+}
Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/ViewScopeProxyMap.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/impl/DefaultViewScopeHandler.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/impl/DefaultViewScopeHandler.java?rev=1513021&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/impl/DefaultViewScopeHandler.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/impl/DefaultViewScopeHandler.java Sun Aug 11 23:54:52 2013
@@ -0,0 +1,147 @@
+/*
+ * 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.view.impl;
+
+import java.math.BigInteger;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import org.apache.myfaces.spi.ViewScopeProvider;
+
+/**
+ * Minimal implementation for view scope without CDI but always store
+ * the beans into session.
+ *
+ * @author Leonardo Uribe
+ */
+public class DefaultViewScopeHandler extends ViewScopeProvider
+{
+ private static final String VIEW_SCOPE_PREFIX = "oam.view.SCOPE";
+
+ private static final String VIEW_SCOPE_PREFIX_KEY = VIEW_SCOPE_PREFIX+".KEY";
+
+ private static final String VIEW_SCOPE_PREFIX_MAP = VIEW_SCOPE_PREFIX+".MAP";
+
+ static final char SEPARATOR_CHAR = '.';
+
+ private final AtomicLong _count;
+
+ public DefaultViewScopeHandler()
+ {
+ _count = new AtomicLong(_getSeed());
+ }
+
+ /**
+ * Returns a cryptographically secure random number to use as the _count seed
+ */
+ private static long _getSeed()
+ {
+ SecureRandom rng;
+ try
+ {
+ // try SHA1 first
+ rng = SecureRandom.getInstance("SHA1PRNG");
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // SHA1 not present, so try the default (which could potentially not be
+ // cryptographically secure)
+ rng = new SecureRandom();
+ }
+
+ // use 48 bits for strength and fill them in
+ byte[] randomBytes = new byte[6];
+ rng.nextBytes(randomBytes);
+
+ // convert to a long
+ return new BigInteger(randomBytes).longValue();
+ }
+
+ /**
+ * Get the next token to be assigned to this request
+ *
+ * @return
+ */
+ private String _getNextToken()
+ {
+ // atomically increment the value
+ long nextToken = _count.incrementAndGet();
+
+ // convert using base 36 because it is a fast efficient subset of base-64
+ return Long.toString(nextToken, 36);
+ }
+
+ public void onSessionDestroyed()
+ {
+ // TODO: Implement @PreDestroy? In JSF 2.0 this part was not present,
+ // but in theory we should do it here.
+ }
+
+ public Map<String, Object> createViewScopeMap(FacesContext facesContext, String viewScopeId)
+ {
+ String fullToken = VIEW_SCOPE_PREFIX_MAP + SEPARATOR_CHAR + viewScopeId;
+ Map<String, Object> map = _createSubKeyMap(facesContext, fullToken);
+ return map;
+ }
+
+ public Map<String, Object> restoreViewScopeMap(FacesContext facesContext, String viewScopeId)
+ {
+ String fullToken = VIEW_SCOPE_PREFIX_MAP + SEPARATOR_CHAR + viewScopeId;
+ Map<String, Object> map = _createSubKeyMap(facesContext, fullToken);
+ return map;
+ }
+
+ private Map<String, Object> _createSubKeyMap(FacesContext context, String prefix)
+ {
+ ExternalContext external = context.getExternalContext();
+ Map<String, Object> sessionMap = external.getSessionMap();
+
+ return new SubKeyMap<Object>(sessionMap, prefix);
+ }
+
+ public String generateViewScopeId(FacesContext facesContext)
+ {
+ // To ensure uniqueness in this part we use a counter that
+ // is stored into session and we add a random number to
+ // make difficult to guess the next number.
+ ExternalContext externalContext = facesContext.getExternalContext();
+ Object sessionObj = externalContext.getSession(true);
+ Integer sequence = null;
+ // synchronized to increase sequence if multiple requests
+ // are handled at the same time for the session
+ synchronized (sessionObj)
+ {
+ Map<String, Object> map = externalContext.getSessionMap();
+ sequence = (Integer) map.get(VIEW_SCOPE_PREFIX_KEY);
+ if (sequence == null || sequence.intValue() == Integer.MAX_VALUE)
+ {
+ sequence = Integer.valueOf(1);
+ }
+ else
+ {
+ sequence = Integer.valueOf(sequence.intValue());
+ }
+ map.put(VIEW_SCOPE_PREFIX_KEY, sequence);
+ }
+ return _getNextToken()+'_'+sequence.toString();
+ }
+}
Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/impl/DefaultViewScopeHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Copied: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/impl/SubKeyMap.java (from r1509781, myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/cdi/SubKeyMap.java)
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/impl/SubKeyMap.java?p2=myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/impl/SubKeyMap.java&p1=myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/cdi/SubKeyMap.java&r1=1509781&r2=1513021&rev=1513021&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/cdi/SubKeyMap.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/impl/SubKeyMap.java Sun Aug 11 23:54:52 2013
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.myfaces.flow.cdi;
+package org.apache.myfaces.view.impl;
import java.util.AbstractMap;
import java.util.AbstractSet;
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/AbstractFacesInitializer.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/AbstractFacesInitializer.java?rev=1513021&r1=1513020&r2=1513021&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/AbstractFacesInitializer.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/AbstractFacesInitializer.java Sun Aug 11 23:54:52 2013
@@ -53,7 +53,11 @@ import java.util.Locale;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
import org.apache.myfaces.util.ExternalSpecifications;
+import org.apache.myfaces.spi.ViewScopeProvider;
+import org.apache.myfaces.spi.ViewScopeProviderFactory;
/**
* Performs common initialization tasks.
@@ -94,6 +98,11 @@ public abstract class AbstractFacesIniti
@JSFWebConfigParam(expectedValues="true, auto, false", defaultValue="auto")
public static final String INIT_PARAM_LOG_WEB_CONTEXT_PARAMS = "org.apache.myfaces.LOG_WEB_CONTEXT_PARAMS";
public static final String INIT_PARAM_LOG_WEB_CONTEXT_PARAMS_DEFAULT ="auto";
+
+ public static final String CDI_BEAN_MANAGER_INSTANCE = "oam.cdi.BEAN_MANAGER_INSTANCE";
+
+ private static final String CDI_SERVLET_CONTEXT_BEAN_MANAGER_ATTRIBUTE =
+ "javax.enterprise.inject.spi.BeanManager";
/**
* Performs all necessary initialization tasks like configuring this JSF
@@ -141,6 +150,20 @@ public abstract class AbstractFacesIniti
}
initContainerIntegration(servletContext, externalContext);
+
+ initCDIIntegration(servletContext, externalContext);
+
+ ViewScopeProviderFactory factory = ViewScopeProviderFactory.getViewScopeHandlerFactory(
+ externalContext);
+
+ ViewScopeProvider viewScopeHandler = factory.getViewScopeHandler(
+ externalContext);
+
+ ManagedBeanDestroyerListener listener = (ManagedBeanDestroyerListener)
+ externalContext.getApplicationMap().get(
+ ManagedBeanDestroyerListener.APPLICATION_MAP_KEY);
+
+ listener.setViewScopeHandler(viewScopeHandler);
String useEncryption = servletContext.getInitParameter(StateUtils.USE_ENCRYPTION);
if (!"false".equals(useEncryption)) // the default value is true
@@ -499,4 +522,56 @@ public abstract class AbstractFacesIniti
protected abstract void initContainerIntegration(
ServletContext servletContext, ExternalContext externalContext);
+ /**
+ * The intention of this method is provide a point where CDI integration is done.
+ * Faces Flow and javax.faces.view.ViewScope requires CDI in order to work, so
+ * this method should set a BeanManager instance on application map under
+ * the key "oam.cdi.BEAN_MANAGER_INSTANCE". The default implementation look on
+ * ServletContext first and then use JNDI.
+ *
+ * @param servletContext
+ * @param externalContext
+ */
+ protected void initCDIIntegration(
+ ServletContext servletContext, ExternalContext externalContext)
+ {
+ // Lookup bean manager and put it into an application scope attribute to
+ // access it later. Remember the trick here is do not call any CDI api
+ // directly, so if no CDI api is on the classpath no exception will be thrown.
+
+ // Try with servlet context
+ Object beanManager = servletContext.getAttribute(
+ CDI_SERVLET_CONTEXT_BEAN_MANAGER_ATTRIBUTE);
+ if (beanManager == null)
+ {
+ // Try with JNDI
+ try
+ {
+ // in an application server
+ beanManager = InitialContext.doLookup("java:comp/BeanManager");
+ }
+ catch (NamingException e)
+ {
+ // silently ignore
+ }
+
+ if (beanManager == null)
+ {
+ try
+ {
+ // in a servlet container
+ beanManager = InitialContext.doLookup("java:comp/env/BeanManager");
+ }
+ catch (NamingException e)
+ {
+ // silently ignore
+ }
+ }
+ }
+ if (beanManager != null)
+ {
+ externalContext.getApplicationMap().put(CDI_BEAN_MANAGER_INSTANCE,
+ beanManager);
+ }
+ }
}
Modified: 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=1513021&r1=1513020&r2=1513021&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/ManagedBeanDestroyerListener.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/webapp/ManagedBeanDestroyerListener.java Sun Aug 11 23:54:52 2013
@@ -36,6 +36,7 @@ import javax.servlet.http.HttpSessionEve
import javax.servlet.http.HttpSessionListener;
import org.apache.myfaces.config.ManagedBeanDestroyer;
+import org.apache.myfaces.spi.ViewScopeProvider;
/**
* Listens to
@@ -63,6 +64,8 @@ public class ManagedBeanDestroyerListene
public static final String APPLICATION_MAP_KEY = "org.apache.myfaces.ManagedBeanDestroyerListener";
private ManagedBeanDestroyer _destroyer = null;
+
+ private ViewScopeProvider _viewScopeHandler = null;
/**
* Sets the ManagedBeanDestroyer instance to use.
@@ -73,6 +76,11 @@ public class ManagedBeanDestroyerListene
{
_destroyer = destroyer;
}
+
+ public void setViewScopeHandler(ViewScopeProvider listener)
+ {
+ _viewScopeHandler = listener;
+ }
/* Session related methods ***********************************************/
@@ -128,6 +136,17 @@ public class ManagedBeanDestroyerListene
_destroyer.destroy(name, value);
}
}*/
+
+ // If we don't propagate this event, CDI will do for us but outside JSF control
+ // so when @PreDestroy methods are called there will not be an active FacesContext.
+ // The trick here is ensure clean the affected scopes to avoid duplicates.
+ // Remember cdi session scope is different from jsf session scope, because in
+ // jsf case the beans are stored under a session attribute, so it has the problem
+ // with attributeRemoved, but on cdi a wrapper is used instead, avoiding the problem.
+ if (_viewScopeHandler != null)
+ {
+ _viewScopeHandler.onSessionDestroyed();
+ }
}
/* Context related methods ***********************************************/
Modified: myfaces/core/trunk/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension?rev=1513021&r1=1513020&r2=1513021&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension (original)
+++ myfaces/core/trunk/impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension Sun Aug 11 23:54:52 2013
@@ -1,2 +1,3 @@
+org.apache.myfaces.cdi.view.ViewScopeContextExtension
org.apache.myfaces.flow.cdi.FlowBuilderCDIExtension
org.apache.myfaces.flow.cdi.FlowScopeCDIExtension
Modified: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/flow/FlowMyFacesRequestTestCase.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/flow/FlowMyFacesRequestTestCase.java?rev=1513021&r1=1513020&r2=1513021&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/flow/FlowMyFacesRequestTestCase.java (original)
+++ myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/flow/FlowMyFacesRequestTestCase.java Sun Aug 11 23:54:52 2013
@@ -119,6 +119,8 @@ public class FlowMyFacesRequestTestCase
Assert.assertNotNull(currentFlow);
Assert.assertEquals("flow1", currentFlow.getId());
+ facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flow1","value1");
+
processRender();
UICommand button2 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:call_flow2");
@@ -129,6 +131,8 @@ public class FlowMyFacesRequestTestCase
currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
Assert.assertNotNull(currentFlow);
Assert.assertEquals("flow2", currentFlow.getId());
+ Assert.assertFalse(facesContext.getApplication().getFlowHandler().getCurrentFlowScope().containsKey("flow1"));
+ facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flow2","value2");
processRender();