You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by gp...@apache.org on 2013/04/22 03:49:59 UTC

git commit: DELTASPIKE-347 keep faces-messages per default in case of a redirect

Updated Branches:
  refs/heads/master 85a7fdeed -> 566675190


DELTASPIKE-347 keep faces-messages per default in case of a redirect

 (first part - rest depends on DELTASPIKE-289)


Project: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/commit/56667519
Tree: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/tree/56667519
Diff: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/diff/56667519

Branch: refs/heads/master
Commit: 56667519077805eae5e1c1958091c50d67dc264e
Parents: 85a7fde
Author: gpetracek <gp...@apache.org>
Authored: Mon Apr 22 03:31:04 2013 +0200
Committer: gpetracek <gp...@apache.org>
Committed: Mon Apr 22 03:48:45 2013 +0200

----------------------------------------------------------------------
 .../listener/phase/DeltaSpikePhaseListener.java    |   15 +++-
 .../jsf/impl/listener/phase/WindowMetaData.java    |   19 ++++
 .../request/DeltaSpikeExternalContextWrapper.java  |   48 ++++++++++
 .../request/DeltaSpikeFacesContextWrapper.java     |   51 +++++++++++
 .../jsf/impl/message/FacesMessageEntry.java        |   67 ++++++++++++++
 .../apache/deltaspike/jsf/impl/util/JsfUtils.java  |   70 +++++++++++++++
 6 files changed, 268 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/56667519/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/phase/DeltaSpikePhaseListener.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/phase/DeltaSpikePhaseListener.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/phase/DeltaSpikePhaseListener.java
index efc07ea..c5c0672 100644
--- a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/phase/DeltaSpikePhaseListener.java
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/phase/DeltaSpikePhaseListener.java
@@ -27,6 +27,7 @@ import org.apache.deltaspike.core.api.provider.BeanProvider;
 import org.apache.deltaspike.core.spi.activation.Deactivatable;
 import org.apache.deltaspike.core.util.ClassDeactivationUtils;
 import org.apache.deltaspike.jsf.impl.security.ViewRootAccessHandler;
+import org.apache.deltaspike.jsf.impl.util.JsfUtils;
 import org.apache.deltaspike.jsf.impl.util.SecurityUtils;
 import org.apache.deltaspike.jsf.impl.util.ViewControllerUtils;
 import org.apache.deltaspike.security.api.authorization.ErrorViewAwareAccessDeniedException;
@@ -103,7 +104,12 @@ public class DeltaSpikePhaseListener implements PhaseListener, Deactivatable
 
         processInitView(phaseEvent);
 
-        if (PhaseId.RENDER_RESPONSE.equals(phaseEvent.getPhaseId()))
+        if (PhaseId.RESTORE_VIEW.equals(phaseEvent.getPhaseId()))
+        {
+            onAfterRestoreView(phaseEvent.getFacesContext());
+
+        }
+        else if (PhaseId.RENDER_RESPONSE.equals(phaseEvent.getPhaseId()))
         {
             onAfterRenderResponse(phaseEvent.getFacesContext());
         }
@@ -112,6 +118,11 @@ public class DeltaSpikePhaseListener implements PhaseListener, Deactivatable
         this.jsfRequestLifecyclePhaseListener.afterPhase(phaseEvent);
     }
 
+    private void onAfterRestoreView(FacesContext facesContext)
+    {
+        JsfUtils.tryToRestoreMessages(facesContext);
+    }
+
     private void onAfterRenderResponse(FacesContext facesContext)
     {
         processPostRenderView(facesContext);
@@ -209,7 +220,7 @@ public class DeltaSpikePhaseListener implements PhaseListener, Deactivatable
         }
         catch (ContextNotActiveException e)
         {
-            return; //TODO discuss how we handle it
+            //TODO discuss how we handle it
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/56667519/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/phase/WindowMetaData.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/phase/WindowMetaData.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/phase/WindowMetaData.java
index d7f1c83..3360aee 100644
--- a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/phase/WindowMetaData.java
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/phase/WindowMetaData.java
@@ -19,8 +19,10 @@
 package org.apache.deltaspike.jsf.impl.listener.phase;
 
 import org.apache.deltaspike.core.api.scope.WindowScoped;
+import org.apache.deltaspike.jsf.impl.message.FacesMessageEntry;
 
 import java.io.Serializable;
+import java.util.List;
 
 @WindowScoped
 public class WindowMetaData implements Serializable
@@ -29,6 +31,13 @@ public class WindowMetaData implements Serializable
 
     private String initializedViewId;
 
+    /**
+     * used per default instead of Flash#setKeepMessages,
+     * because there are less issues in view of multi-window support esp. before jsf v2.2 and
+     * a custom window-handler might have special requirements.
+     */
+    private List<FacesMessageEntry> facesMessageEntryList;
+
     public String getInitializedViewId()
     {
         return initializedViewId;
@@ -38,4 +47,14 @@ public class WindowMetaData implements Serializable
     {
         this.initializedViewId = initializedViewId;
     }
+
+    public void setFacesMessageEntryList(List<FacesMessageEntry> facesMessageEntryList)
+    {
+        this.facesMessageEntryList = facesMessageEntryList;
+    }
+
+    public List<FacesMessageEntry> getFacesMessageEntryList()
+    {
+        return facesMessageEntryList;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/56667519/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeExternalContextWrapper.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeExternalContextWrapper.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeExternalContextWrapper.java
new file mode 100644
index 0000000..afa9782
--- /dev/null
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeExternalContextWrapper.java
@@ -0,0 +1,48 @@
+/*
+ * 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.spi.activation.Deactivatable;
+import org.apache.deltaspike.jsf.impl.util.JsfUtils;
+
+import javax.faces.context.ExternalContext;
+import javax.faces.context.ExternalContextWrapper;
+import java.io.IOException;
+
+public class DeltaSpikeExternalContextWrapper extends ExternalContextWrapper implements Deactivatable
+{
+    private final ExternalContext wrapped;
+
+    DeltaSpikeExternalContextWrapper(ExternalContext wrapped)
+    {
+        this.wrapped = wrapped;
+    }
+
+    @Override
+    public void redirect(String url) throws IOException
+    {
+        JsfUtils.saveFacesMessages(this.wrapped);
+        this.wrapped.redirect(url);
+    }
+
+    public ExternalContext getWrapped()
+    {
+        return wrapped;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/56667519/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeFacesContextWrapper.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeFacesContextWrapper.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeFacesContextWrapper.java
index f1985e1..2c995a5 100644
--- a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeFacesContextWrapper.java
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeFacesContextWrapper.java
@@ -22,10 +22,16 @@ import org.apache.deltaspike.core.api.config.view.metadata.ViewConfigResolver;
 import org.apache.deltaspike.core.api.provider.BeanProvider;
 import org.apache.deltaspike.core.util.ClassDeactivationUtils;
 import org.apache.deltaspike.jsf.impl.config.view.DefaultErrorViewAwareExceptionHandlerWrapper;
+import org.apache.deltaspike.jsf.impl.message.FacesMessageEntry;
 
+import javax.faces.application.FacesMessage;
 import javax.faces.context.ExceptionHandler;
+import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
 import javax.faces.context.FacesContextWrapper;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 class DeltaSpikeFacesContextWrapper extends FacesContextWrapper
 {
@@ -35,10 +41,22 @@ class DeltaSpikeFacesContextWrapper extends FacesContextWrapper
 
     private boolean defaultErrorViewExceptionHandlerActivated;
 
+    private ExternalContext wrappedExternalContext;
+
     DeltaSpikeFacesContextWrapper(FacesContext wrappedFacesContext)
     {
         this.wrappedFacesContext = wrappedFacesContext;
 
+        if (ClassDeactivationUtils.isActivated(DeltaSpikeExternalContextWrapper.class))
+        {
+            this.wrappedExternalContext =
+                    new DeltaSpikeExternalContextWrapper(wrappedFacesContext.getExternalContext());
+        }
+        else
+        {
+            this.wrappedExternalContext = wrappedFacesContext.getExternalContext();
+        }
+
         setCurrentInstance(this);
     }
 
@@ -99,6 +117,39 @@ class DeltaSpikeFacesContextWrapper extends FacesContextWrapper
         }
     }
 
+    /**
+     * Adds the {@link FacesMessage} also to a request scoped list to allow to preserve them later on
+     * (in case of redirects)
+     *
+     * {@inheritDoc}
+     */
+    @Override
+    public void addMessage(String componentId, FacesMessage facesMessage)
+    {
+        this.wrappedFacesContext.addMessage(componentId, facesMessage);
+
+        //don't store it directly in the window context - it would trigger a too early restore (in some cases)
+        Map<String, Object> requestMap = getExternalContext().getRequestMap();
+
+        @SuppressWarnings({ "unchecked" })
+        List<FacesMessageEntry> facesMessageEntryList =
+                (List<FacesMessageEntry>)requestMap.get(FacesMessageEntry.class.getName());
+
+        if (facesMessageEntryList == null)
+        {
+            facesMessageEntryList = new CopyOnWriteArrayList<FacesMessageEntry>();
+            requestMap.put(FacesMessageEntry.class.getName(), facesMessageEntryList);
+        }
+
+        facesMessageEntryList.add(new FacesMessageEntry(componentId, facesMessage));
+    }
+
+    @Override
+    public ExternalContext getExternalContext()
+    {
+        return this.wrappedExternalContext;
+    }
+
     @Override
     public FacesContext getWrapped()
     {

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/56667519/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/message/FacesMessageEntry.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/message/FacesMessageEntry.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/message/FacesMessageEntry.java
new file mode 100644
index 0000000..b41020e
--- /dev/null
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/message/FacesMessageEntry.java
@@ -0,0 +1,67 @@
+/*
+ * 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.message;
+
+import javax.enterprise.inject.Typed;
+import javax.faces.application.FacesMessage;
+import java.io.Serializable;
+
+/**
+ * Entry for {@link FacesMessage} which have to be stored longer than a request
+ */
+@Typed()
+public class FacesMessageEntry implements Serializable
+{
+    private static final long serialVersionUID = 6831499672107426470L;
+    private String componentId;
+    private FacesMessage facesMessage;
+
+    protected FacesMessageEntry()
+    {
+    }
+
+    /**
+     * Constructor for creating the entry for the given component-id and {@link FacesMessage}
+     * @param componentId current component-id
+     * @param facesMessage current faces-message
+     */
+    public FacesMessageEntry(String componentId, FacesMessage facesMessage)
+    {
+        this.componentId = componentId;
+        this.facesMessage = facesMessage;
+    }
+
+    /**
+     * Returns the current component-id
+     * @return component-id of the entry
+     */
+    public String getComponentId()
+    {
+        return componentId;
+    }
+
+    /**
+     * Returns the current {@link FacesMessage}
+     * @return faces-message of the entry
+     */
+    public FacesMessage getFacesMessage()
+    {
+        return facesMessage;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/56667519/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/util/JsfUtils.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/util/JsfUtils.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/util/JsfUtils.java
index 734ebb0..63a752a 100644
--- a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/util/JsfUtils.java
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/util/JsfUtils.java
@@ -21,14 +21,20 @@ package org.apache.deltaspike.jsf.impl.util;
 import org.apache.deltaspike.core.api.config.view.metadata.ViewConfigResolver;
 import org.apache.deltaspike.core.api.provider.BeanProvider;
 import org.apache.deltaspike.core.api.config.view.navigation.NavigationParameterContext;
+import org.apache.deltaspike.jsf.api.config.JsfModuleConfig;
+import org.apache.deltaspike.jsf.impl.listener.phase.WindowMetaData;
+import org.apache.deltaspike.jsf.impl.message.FacesMessageEntry;
 
+import javax.enterprise.context.ContextNotActiveException;
 import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 public abstract class JsfUtils
 {
@@ -144,4 +150,68 @@ public abstract class JsfUtils
     {
         return BeanProvider.getContextualReference(ViewConfigResolver.class);
     }
+
+    public static void saveFacesMessages(ExternalContext externalContext)
+    {
+        JsfModuleConfig jsfModuleConfig = BeanProvider.getContextualReference(JsfModuleConfig.class);
+
+        if (!jsfModuleConfig.isAlwaysKeepMessages())
+        {
+            return;
+        }
+
+        try
+        {
+            WindowMetaData windowMetaData = BeanProvider.getContextualReference(WindowMetaData.class);
+
+            Map<String, Object> requestMap = externalContext.getRequestMap();
+
+            @SuppressWarnings({ "unchecked" })
+            List<FacesMessageEntry> facesMessageEntryList =
+                    (List<FacesMessageEntry>)requestMap.get(FacesMessageEntry.class.getName());
+
+            if (facesMessageEntryList == null)
+            {
+                facesMessageEntryList = new CopyOnWriteArrayList<FacesMessageEntry>();
+            }
+            windowMetaData.setFacesMessageEntryList(facesMessageEntryList);
+        }
+        catch (ContextNotActiveException e)
+        {
+            //TODO log it in case of project-stage development
+            //we can't handle it correctly -> delegate to the jsf-api (which has some restrictions esp. before v2.2)
+            FacesContext.getCurrentInstance().getExternalContext().getFlash().setKeepMessages(true);
+        }
+    }
+
+    public static void tryToRestoreMessages(FacesContext facesContext)
+    {
+        JsfModuleConfig jsfModuleConfig = BeanProvider.getContextualReference(JsfModuleConfig.class);
+
+        if (!jsfModuleConfig.isAlwaysKeepMessages())
+        {
+            return;
+        }
+
+        try
+        {
+            WindowMetaData windowMetaData = BeanProvider.getContextualReference(WindowMetaData.class);
+
+            @SuppressWarnings({ "unchecked" })
+            List<FacesMessageEntry> facesMessageEntryList = windowMetaData.getFacesMessageEntryList();
+
+            if (facesMessageEntryList != null)
+            {
+                for (FacesMessageEntry facesMessageEntry : facesMessageEntryList)
+                {
+                    facesContext.addMessage(facesMessageEntry.getComponentId(), facesMessageEntry.getFacesMessage());
+                }
+                facesMessageEntryList.clear();
+            }
+        }
+        catch (ContextNotActiveException e)
+        {
+            //TODO discuss how we handle it
+        }
+    }
 }