Author: lincolnthree
Date: 2010-03-11 18:09:39 -0500 (Thu, 11 Mar 2010)
New Revision: 12182
Added:
modules/faces/trunk/src/main/java/META-INF/
modules/faces/trunk/src/main/java/META-INF/MANIFEST.MF
modules/faces/trunk/src/main/java/javax/
modules/faces/trunk/src/main/java/javax/faces/
modules/faces/trunk/src/main/java/javax/faces/bean/
modules/faces/trunk/src/main/java/javax/faces/bean/FlashScoped.java
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/FlashScopedContext.java
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/FlashScopedExtension.java
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/ViewScopedContext.java
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/ViewScopedExtension.java
Removed:
modules/faces/trunk/src/main/java/org/jboss/seam/faces/scopes/
Modified:
modules/faces/trunk/pom.xml
modules/faces/trunk/src/main/resources/META-INF/faces-config.xml
modules/faces/trunk/src/main/resources/META-INF/seam-faces.taglib.xml
modules/faces/trunk/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
Log:
* FlashScope is functional (perhaps barely, but functional)
Modified: modules/faces/trunk/pom.xml
===================================================================
--- modules/faces/trunk/pom.xml 2010-03-11 15:47:36 UTC (rev 12181)
+++ modules/faces/trunk/pom.xml 2010-03-11 23:09:39 UTC (rev 12182)
@@ -10,8 +10,8 @@
</parent>
<artifactId>seam-faces</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
- <version>3.0.0-SNAPSHOT</version>
<name>Seam Faces Module</name>
<!-- Snapshots repo to get parent -->
Added: modules/faces/trunk/src/main/java/META-INF/MANIFEST.MF
===================================================================
--- modules/faces/trunk/src/main/java/META-INF/MANIFEST.MF (rev
0)
+++ modules/faces/trunk/src/main/java/META-INF/MANIFEST.MF 2010-03-11 23:09:39 UTC (rev
12182)
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path:
+
Added: modules/faces/trunk/src/main/java/javax/faces/bean/FlashScoped.java
===================================================================
--- modules/faces/trunk/src/main/java/javax/faces/bean/FlashScoped.java
(rev 0)
+++ modules/faces/trunk/src/main/java/javax/faces/bean/FlashScoped.java 2010-03-11
23:09:39 UTC (rev 12182)
@@ -0,0 +1,25 @@
+package javax.faces.bean;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+import javax.enterprise.context.NormalScope;
+
+/**
+ * Defines a CDI bean as Flash scoped. A bean put in the JSF2 flash will survive
+ * one page transition, or navigation, then be cleared.
+ *
+ * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter,
III</a>
+ */
+@NormalScope
+@Inherited
+@Documented
+(a)Target(ElementType.TYPE)
+@Retention(value = RetentionPolicy.RUNTIME)
+public @interface FlashScoped {
+
+}
Added:
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/FlashScopedContext.java
===================================================================
---
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/FlashScopedContext.java
(rev 0)
+++
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/FlashScopedContext.java 2010-03-11
23:09:39 UTC (rev 12182)
@@ -0,0 +1,165 @@
+package org.jboss.seam.faces.context;
+
+import java.lang.annotation.Annotation;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.enterprise.context.ContextNotActiveException;
+import javax.enterprise.context.spi.Context;
+import javax.enterprise.context.spi.Contextual;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.faces.bean.FlashScoped;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.context.Flash;
+import javax.faces.event.PhaseEvent;
+import javax.faces.event.PhaseId;
+import javax.faces.event.PhaseListener;
+
+/**
+ * This class provides the contexts lifecycle for the new JSF2 Flash Context
+ *
+ * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter,
III</a>
+ */
+public class FlashScopedContext implements Context, PhaseListener
+{
+ private final static String COMPONENT_MAP_NAME =
"org.jboss.seam.faces.flash.componentInstanceMap";
+ private final static String CREATIONAL_MAP_NAME =
"org.jboss.seam.faces.flash.creationalInstanceMap";
+ private final ThreadLocal<Map<Contextual<?>, Object>>
lastComponentInstanceMap = new ThreadLocal<Map<Contextual<?>,
Object>>();
+ private final ThreadLocal<Map<Contextual<?>,
CreationalContext<?>>> lastCreationalContextMap = new
ThreadLocal<Map<Contextual<?>, CreationalContext<?>>>();
+
+ @SuppressWarnings("unchecked")
+ public <T> T get(final Contextual<T> component)
+ {
+ assertActive();
+ Map<Contextual<?>, Object> componentInstanceMap =
getComponentInstanceMap();
+ T instance = (T) componentInstanceMap.get(component);
+ return instance;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> T get(final Contextual<T> component, final
CreationalContext<T> creationalContext)
+ {
+ assertActive();
+
+ T instance = get(component);
+
+ if (instance == null)
+ {
+ Map<Contextual<?>, CreationalContext<?>>
creationalContextMap = getCreationalContextMap();
+ Map<Contextual<?>, Object> componentInstanceMap =
getComponentInstanceMap();
+
+ synchronized (componentInstanceMap)
+ {
+ instance = (T) componentInstanceMap.get(component);
+ if (instance == null)
+ {
+ instance = component.create(creationalContext);
+
+ if (instance != null)
+ {
+ componentInstanceMap.put(component, instance);
+ creationalContextMap.put(component, creationalContext);
+ }
+ }
+ }
+ }
+
+ return instance;
+ }
+
+ public Class<? extends Annotation> getScope()
+ {
+ return FlashScoped.class;
+ }
+
+ private Flash getFlash()
+ {
+ FacesContext currentInstance = FacesContext.getCurrentInstance();
+ if (currentInstance != null)
+ {
+ ExternalContext externalContext = currentInstance.getExternalContext();
+ return externalContext.getFlash();
+ }
+ return null;
+ }
+
+ public boolean isActive()
+ {
+ return getFlash() != null;
+ }
+
+ private void assertActive()
+ {
+ if (!isActive())
+ {
+ throw new ContextNotActiveException(
+ "WebBeans context with scope annotation @FlashScoped is not
active with respect to the current thread");
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private Map<Contextual<?>, Object> getComponentInstanceMap()
+ {
+ Flash flash = getFlash();
+ ConcurrentHashMap<Contextual<?>, Object> map =
(ConcurrentHashMap<Contextual<?>, Object>) flash
+ .get(COMPONENT_MAP_NAME);
+ if (map == null)
+ {
+ map = new ConcurrentHashMap<Contextual<?>, Object>();
+ flash.put(COMPONENT_MAP_NAME, map);
+ }
+ return map;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Map<Contextual<?>, CreationalContext<?>>
getCreationalContextMap()
+ {
+ Flash flash = getFlash();
+ Map<Contextual<?>, CreationalContext<?>> map =
(ConcurrentHashMap<Contextual<?>, CreationalContext<?>>) flash
+ .get(CREATIONAL_MAP_NAME);
+ if (map == null)
+ {
+ map = new ConcurrentHashMap<Contextual<?>,
CreationalContext<?>>();
+ flash.put(CREATIONAL_MAP_NAME, map);
+ }
+ return map;
+ }
+
+ public void beforePhase(final PhaseEvent event)
+ {
+ this.lastComponentInstanceMap.set(getComponentInstanceMap());
+ this.lastCreationalContextMap.set(getCreationalContextMap());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void afterPhase(final PhaseEvent event)
+ {
+ // TODO verify that this is actually destroying the beans we want to be
+ // destroyed... flash is confusing, tests will make sense of it
+ Map<Contextual<?>, Object> componentInstanceMap =
lastComponentInstanceMap.get();
+ Map<Contextual<?>, CreationalContext<?>> creationalContextMap =
lastCreationalContextMap.get();
+
+ if (componentInstanceMap != null)
+ {
+ for (Entry<Contextual<?>, Object> componentEntry :
componentInstanceMap.entrySet())
+ {
+ Contextual contextual = componentEntry.getKey();
+ Object instance = componentEntry.getValue();
+ CreationalContext creational = creationalContextMap.get(contextual);
+
+ contextual.destroy(instance, creational);
+ }
+ }
+
+ this.lastComponentInstanceMap.remove();
+ this.lastCreationalContextMap.remove();
+ }
+
+ public PhaseId getPhaseId()
+ {
+ return PhaseId.RENDER_RESPONSE;
+ }
+
+}
Added:
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/FlashScopedExtension.java
===================================================================
---
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/FlashScopedExtension.java
(rev 0)
+++
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/FlashScopedExtension.java 2010-03-11
23:09:39 UTC (rev 12182)
@@ -0,0 +1,32 @@
+/*
+ * To change this template, choose Tools | Templates and open the template in
+ * the editor.
+ */
+
+package org.jboss.seam.faces.context;
+
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AfterBeanDiscovery;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
+import javax.enterprise.inject.spi.Extension;
+import javax.faces.bean.FlashScoped;
+
+/**
+ * An extension to provide @FlashScoped CDI / JSF2 integration.
+ *
+ * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter,
III</a>
+ */
+public class FlashScopedExtension implements Extension
+{
+
+ public void addScope(@Observes final BeforeBeanDiscovery event)
+ {
+ event.addScope(FlashScoped.class, true, true);
+ }
+
+ public void registerContext(@Observes final AfterBeanDiscovery event)
+ {
+ event.addContext(new FlashScopedContext());
+ }
+
+}
Copied:
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/ViewScopedContext.java
(from rev 12181,
modules/faces/trunk/src/main/java/org/jboss/seam/faces/scopes/ViewScopedContext.java)
===================================================================
--- modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/ViewScopedContext.java
(rev 0)
+++
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/ViewScopedContext.java 2010-03-11
23:09:39 UTC (rev 12182)
@@ -0,0 +1,228 @@
+/*
+ * 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.jboss.seam.faces.context;
+
+import java.lang.annotation.Annotation;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.enterprise.context.ContextNotActiveException;
+import javax.enterprise.context.spi.Context;
+import javax.enterprise.context.spi.Contextual;
+import javax.enterprise.context.spi.CreationalContext;
+
+import javax.faces.bean.ViewScoped;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+import javax.faces.event.PreDestroyViewMapEvent;
+import javax.faces.event.SystemEvent;
+import javax.faces.event.SystemEventListener;
+
+/**
+ * This class provides the contexts lifecycle for the new JSF-2 @ViewScoped
+ * Context
+ *
+ * @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a>
+ * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter,
III</a>
+ */
+public class ViewScopedContext implements Context, SystemEventListener
+{
+
+ private final static String COMPONENT_MAP_NAME =
"org.jboss.seam.faces.viewscope.componentInstanceMap";
+ private final static String CREATIONAL_MAP_NAME =
"org.jboss.seam.faces.viewscope.creationalInstanceMap";
+
+ private boolean isJsfSubscribed = false;
+
+ @SuppressWarnings("unchecked")
+ public <T> T get(final Contextual<T> component)
+ {
+ assertActive();
+
+ if (!isJsfSubscribed)
+ {
+
FacesContext.getCurrentInstance().getApplication().subscribeToEvent(PreDestroyViewMapEvent.class,
this);
+
+ isJsfSubscribed = true;
+ }
+
+ Map<String, Object> viewMap = getViewMap();
+
+ ConcurrentHashMap<Contextual<?>, Object> componentInstanceMap =
(ConcurrentHashMap<Contextual<?>, Object>) viewMap
+ .get(COMPONENT_MAP_NAME);
+
+ if (componentInstanceMap == null)
+ {
+ return null;
+ }
+
+ T instance = (T) componentInstanceMap.get(component);
+
+ return instance;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> T get(final Contextual<T> component, final
CreationalContext<T> creationalContext)
+ {
+ assertActive();
+
+ Map<String, Object> viewMap = getViewMap();
+
+ ConcurrentHashMap<Contextual<?>, Object> componentInstanceMap =
(ConcurrentHashMap<Contextual<?>, Object>) viewMap
+ .get(COMPONENT_MAP_NAME);
+
+ if (componentInstanceMap == null)
+ {
+ // TODO we now need to start being carefull with reentrancy...
+ componentInstanceMap = new ConcurrentHashMap<Contextual<?>,
Object>();
+ viewMap.put(COMPONENT_MAP_NAME, componentInstanceMap);
+ }
+
+ ConcurrentHashMap<Contextual<?>, CreationalContext<?>>
creationalContextMap = (ConcurrentHashMap<Contextual<?>,
CreationalContext<?>>) viewMap
+ .get(CREATIONAL_MAP_NAME);
+ if (creationalContextMap == null)
+ {
+ // TODO we now need to start being carefull with reentrancy...
+ creationalContextMap = new ConcurrentHashMap<Contextual<?>,
CreationalContext<?>>();
+ viewMap.put(CREATIONAL_MAP_NAME, creationalContextMap);
+ }
+
+ T instance = (T) componentInstanceMap.get(component);
+ if (instance != null)
+ {
+ return instance;
+ }
+
+ if (creationalContext == null)
+ {
+ return null;
+ }
+
+ synchronized (componentInstanceMap)
+ {
+ // just to make sure...
+ T i = (T) componentInstanceMap.get(component);
+ if (i != null)
+ {
+ return i;
+ }
+
+ instance = component.create(creationalContext);
+
+ if (instance != null)
+ {
+ componentInstanceMap.put(component, instance);
+ creationalContextMap.put(component, creationalContext);
+ }
+ }
+
+ return instance;
+ }
+
+ public Class<? extends Annotation> getScope()
+ {
+ return ViewScoped.class;
+ }
+
+ /**
+ * The view context is active if a valid ViewRoot could be detected.
+ */
+ public boolean isActive()
+ {
+ return getViewRoot() != null;
+ }
+
+ private void assertActive()
+ {
+ if (!isActive())
+ {
+ throw new ContextNotActiveException(
+ "WebBeans context with scope annotation @ViewScoped is not
active with respect to the current thread");
+ }
+ }
+
+ public boolean isListenerForSource(final Object source)
+ {
+ if (source instanceof UIViewRoot)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * We get PreDestroyViewMapEvent events from the JSF servlet and destroy our
+ * contextual instances. This should (theoretically!) also get fired if the
+ * webapp closes, so there should be no need to manually track all view
+ * scopes and destroy them at a shutdown.
+ *
+ * @see
javax.faces.event.SystemEventListener#processEvent(javax.faces.event.SystemEvent)
+ */
+ @SuppressWarnings("unchecked")
+ public void processEvent(final SystemEvent event)
+ {
+ if (event instanceof PreDestroyViewMapEvent)
+ {
+ // better use the viewmap we get from the event to prevent
+ // concurrent modification problems
+ Map<String, Object> viewMap = ((UIViewRoot)
event.getSource()).getViewMap();
+
+ ConcurrentHashMap<Contextual<?>, Object> componentInstanceMap =
(ConcurrentHashMap<Contextual<?>, Object>) viewMap
+ .get(COMPONENT_MAP_NAME);
+
+ ConcurrentHashMap<Contextual<?>, CreationalContext<?>>
creationalContextMap = (ConcurrentHashMap<Contextual<?>,
CreationalContext<?>>) viewMap
+ .get(CREATIONAL_MAP_NAME);
+
+ if (componentInstanceMap != null)
+ {
+ for (Entry<Contextual<?>, Object> componentEntry :
componentInstanceMap.entrySet())
+ {
+ // there is no nice way to explain the Java Compiler that we
+ // are handling the same type T,
+ // therefore we need completely drop the type information :(
+ Contextual contextual = componentEntry.getKey();
+ Object instance = componentEntry.getValue();
+ CreationalContext creational = creationalContextMap.get(contextual);
+
+ contextual.destroy(instance, creational);
+ }
+ }
+ }
+ }
+
+ protected UIViewRoot getViewRoot()
+ {
+ FacesContext context = FacesContext.getCurrentInstance();
+
+ if (context != null)
+ {
+ return context.getViewRoot();
+ }
+
+ return null;
+ }
+
+ protected Map<String, Object> getViewMap()
+ {
+ UIViewRoot viewRoot = getViewRoot();
+
+ if (viewRoot != null)
+ {
+ return viewRoot.getViewMap(true);
+ }
+
+ return null;
+ }
+}
\ No newline at end of file
Copied:
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/ViewScopedExtension.java
(from rev 12181,
modules/faces/trunk/src/main/java/org/jboss/seam/faces/scopes/ViewScopedExtension.java)
===================================================================
---
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/ViewScopedExtension.java
(rev 0)
+++
modules/faces/trunk/src/main/java/org/jboss/seam/faces/context/ViewScopedExtension.java 2010-03-11
23:09:39 UTC (rev 12182)
@@ -0,0 +1,32 @@
+/*
+ * To change this template, choose Tools | Templates and open the template in
+ * the editor.
+ */
+
+package org.jboss.seam.faces.context;
+
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AfterBeanDiscovery;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
+import javax.enterprise.inject.spi.Extension;
+import javax.faces.bean.ViewScoped;
+
+/**
+ * An extension to provide @ViewScoped CDI / JSF2 integration.
+ *
+ * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter,
III</a>
+ */
+public class ViewScopedExtension implements Extension
+{
+
+ public void addScope(@Observes final BeforeBeanDiscovery event)
+ {
+ event.addScope(ViewScoped.class, true, true);
+ }
+
+ public void registerContext(@Observes final AfterBeanDiscovery event)
+ {
+ event.addContext(new ViewScopedContext());
+ }
+
+}
Modified: modules/faces/trunk/src/main/resources/META-INF/faces-config.xml
===================================================================
--- modules/faces/trunk/src/main/resources/META-INF/faces-config.xml 2010-03-11 15:47:36
UTC (rev 12181)
+++ modules/faces/trunk/src/main/resources/META-INF/faces-config.xml 2010-03-11 23:09:39
UTC (rev 12182)
@@ -12,7 +12,13 @@
<name>webbeans</name>
</after>
</ordering>
-
+
+
+ <lifecycle>
+
<phase-listener>org.jboss.seam.faces.context.FlashScopedContext</phase-listener>
+ </lifecycle>
+
+ <!--
<factory>
<application-factory>org.jboss.seam.faces.application.SeamApplicationFactory</application-factory>
</factory>
@@ -29,9 +35,7 @@
</application>
<lifecycle>
- <!-- Not ready for this yet, it is just testing
<phase-listener>org.jboss.seam.faces.lifecycle.SeamPhaseListener</phase-listener>
- -->
</lifecycle>
<component>
@@ -43,6 +47,7 @@
<component-type>org.jboss.seam.faces.RestrictView</component-type>
<component-class>org.jboss.seam.faces.component.UIRestrictView</component-class>
</component>
+ -->
<component>
<component-type>org.jboss.seam.faces.ViewAction</component-type>
Modified: modules/faces/trunk/src/main/resources/META-INF/seam-faces.taglib.xml
===================================================================
--- modules/faces/trunk/src/main/resources/META-INF/seam-faces.taglib.xml 2010-03-11
15:47:36 UTC (rev 12181)
+++ modules/faces/trunk/src/main/resources/META-INF/seam-faces.taglib.xml 2010-03-11
23:09:39 UTC (rev 12182)
@@ -5,21 +5,6 @@
<
namespace>http://jboss.com/products/seam/faces</namespace>
<tag>
- <tag-name>import</tag-name>
- <component>
- <component-type>org.jboss.seam.faces.Import</component-type>
- </component>
- </tag>
-
- <tag>
- <tag-name>restrictView</tag-name>
- <component>
- <component-type>org.jboss.seam.faces.RestrictView</component-type>
-
<handler-class>org.jboss.seam.faces.facelets.DeferredValueExpressionHandler</handler-class>
- </component>
- </tag>
-
- <tag>
<tag-name>viewAction</tag-name>
<component>
<component-type>org.jboss.seam.faces.ViewAction</component-type>
Modified:
modules/faces/trunk/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
===================================================================
---
modules/faces/trunk/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension 2010-03-11
15:47:36 UTC (rev 12181)
+++
modules/faces/trunk/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension 2010-03-11
23:09:39 UTC (rev 12182)
@@ -1 +1,2 @@
-org.jboss.seam.faces.scopes.ViewScopedExtension
\ No newline at end of file
+org.jboss.seam.faces.context.ViewScopedExtension
+org.jboss.seam.faces.context.FlashScopedExtension
\ No newline at end of file