View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.myfaces.lifecycle;
21  
22  import java.util.HashMap;
23  import java.util.Map;
24  import javax.faces.context.FacesContext;
25  import javax.faces.event.ExceptionQueuedEvent;
26  import javax.faces.event.ExceptionQueuedEventContext;
27  import javax.faces.event.PhaseEvent;
28  import javax.faces.event.PhaseId;
29  import javax.faces.event.PhaseListener;
30  import javax.faces.lifecycle.Lifecycle;
31  
32  /**
33   * This class encapsulates the logic used to call PhaseListeners. It was needed because of issue 9 of the JSF 1.2 spec.
34   * See section 11.3 for more details.
35   * 
36   * @author Stan Silvert
37   */
38  class PhaseListenerManager
39  {
40      private Lifecycle lifecycle;
41      private FacesContext facesContext;
42      private PhaseListener[] phaseListeners;
43  
44      // Tracks success in the beforePhase. Listeners that throw an exception
45      // in beforePhase or were never called because a previous listener threw
46      // an exception should not have its afterPhase called
47      private Map<PhaseId, boolean[]> listenerSuccessMap = new HashMap<PhaseId, boolean[]>();
48  
49      /** Creates a new instance of PhaseListenerManager */
50      PhaseListenerManager(Lifecycle lifecycle, FacesContext facesContext, PhaseListener[] phaseListeners)
51      {
52          this.lifecycle = lifecycle;
53          this.facesContext = facesContext;
54          this.phaseListeners = phaseListeners;
55      }
56  
57      private boolean isListenerForThisPhase(PhaseListener phaseListener, PhaseId phaseId)
58      {
59          int listenerPhaseId = phaseListener.getPhaseId().getOrdinal();
60          return (listenerPhaseId == PhaseId.ANY_PHASE.getOrdinal() || listenerPhaseId == phaseId.getOrdinal());
61      }
62  
63      void informPhaseListenersBefore(PhaseId phaseId)
64      {
65          boolean[] beforePhaseSuccess = new boolean[phaseListeners.length];
66          listenerSuccessMap.put(phaseId, beforePhaseSuccess);
67  
68          PhaseEvent event = new PhaseEvent(facesContext, phaseId, lifecycle);
69  
70          for (int i = 0; i < phaseListeners.length; i++)
71          {
72              PhaseListener phaseListener = phaseListeners[i];
73              if (isListenerForThisPhase(phaseListener, phaseId))
74              {
75                  try
76                  {
77                      phaseListener.beforePhase(event);
78                      beforePhaseSuccess[i] = true;
79                  }
80                  catch (Throwable e)
81                  {
82                      beforePhaseSuccess[i] = false; // redundant - for clarity
83                      
84                      // JSF 2.0: publish exceptions instead of logging them.
85                      
86                      publishException (e, phaseId, ExceptionQueuedEventContext.IN_BEFORE_PHASE_KEY);
87                      
88                      return;
89                  }
90              }
91          }
92      }
93  
94      void informPhaseListenersAfter(PhaseId phaseId)
95      {
96          boolean[] beforePhaseSuccess = listenerSuccessMap.get(phaseId);
97          
98          if (beforePhaseSuccess == null)
99          {
100             // informPhaseListenersBefore method was not called : maybe an exception in LifecycleImpl.executePhase  
101             return;
102         }
103 
104         PhaseEvent event = null;
105 
106         for (int i = phaseListeners.length - 1; i >= 0; i--)
107         {
108             PhaseListener phaseListener = phaseListeners[i];
109             if (isListenerForThisPhase(phaseListener, phaseId) && beforePhaseSuccess[i])
110             {
111                 if (event == null)
112                 {
113                     event = new PhaseEvent(facesContext, phaseId, lifecycle);
114                 }
115                 try
116                 {
117                     phaseListener.afterPhase(event);
118                 }
119                 catch (Throwable e)
120                 {
121                     // JSF 2.0: publish exceptions instead of logging them.
122                     
123                     publishException (e, phaseId, ExceptionQueuedEventContext.IN_AFTER_PHASE_KEY);
124                 }
125             }
126         }
127 
128     }
129     
130     private void publishException (Throwable e, PhaseId phaseId, String key)
131     {
132         ExceptionQueuedEventContext context = new ExceptionQueuedEventContext (facesContext, e, null, phaseId);
133         
134         context.getAttributes().put (key, Boolean.TRUE);
135         
136         facesContext.getApplication().publishEvent (facesContext, ExceptionQueuedEvent.class, context);
137     }
138 }