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.tobago.internal.ajax;
21  
22  import org.slf4j.Logger;
23  import org.slf4j.LoggerFactory;
24  
25  import javax.faces.application.FacesMessage;
26  import javax.faces.application.ViewExpiredException;
27  import javax.faces.component.UIViewRoot;
28  import javax.faces.context.ExternalContext;
29  import javax.faces.context.FacesContext;
30  import javax.faces.event.ExceptionQueuedEvent;
31  import java.io.IOException;
32  import java.util.ArrayList;
33  import java.util.HashMap;
34  import java.util.Iterator;
35  import java.util.List;
36  import java.util.Map;
37  
38  /**
39   * XXX this must be refactored, because of TOBAGO-1524 (see TOBAGO-1563)
40   * @deprecated
41   */
42  @Deprecated
43  public final class AjaxNavigationState {
44  
45    private static final Logger LOG = LoggerFactory.getLogger(AjaxNavigationState.class);
46  
47    private static final String SESSION_KEY = "tobago-AjaxNavigationState";
48  
49    private static final String VIEW_ROOT_KEY = "tobago-AjaxNavigationState-VIEW_ROOT_KEY";
50  
51    private UIViewRoot viewRoot;
52  
53    private Map<String, List<FacesMessage>> messages;
54  
55    private AjaxNavigationState(final FacesContext facesContext) {
56      final ExternalContext externalContext = facesContext.getExternalContext();
57      externalContext.getSessionMap().put(SESSION_KEY, this);
58      viewRoot = facesContext.getViewRoot();
59      messages = new HashMap<String, List<FacesMessage>>();
60      final Iterator<String> iterator = facesContext.getClientIdsWithMessages();
61      while (iterator.hasNext()) {
62        addFacesMessages(facesContext, iterator.next());
63      }
64      if (LOG.isTraceEnabled()) {
65        LOG.trace("Saved viewRoot.getViewId() = \"{}\"", viewRoot.getViewId());
66        for (final Map.Entry<String, List<FacesMessage>> entry : messages.entrySet()) {
67          for (final FacesMessage message : entry.getValue()) {
68            LOG.trace("Saved message \"{}\" : \"{}\"", entry.getKey(), message);
69          }
70        }
71      }
72    }
73  
74    private void addFacesMessages(final FacesContext facesContext, final String clientId) {
75      final Iterator<FacesMessage> facesMessages = facesContext.getMessages(clientId);
76      while (facesMessages.hasNext()) {
77        addFacesMessage(clientId, facesMessages.next());
78      }
79    }
80  
81    private void addFacesMessage(final String clientId, final FacesMessage facesMessage) {
82      List<FacesMessage> facesMessages = messages.get(clientId);
83      if (facesMessages == null) {
84        facesMessages = new ArrayList<FacesMessage>();
85        messages.put(clientId, facesMessages);
86      }
87      facesMessages.add(facesMessage);
88    }
89  
90    private void restoreView(final FacesContext facesContext) {
91      facesContext.setViewRoot(viewRoot);
92      for (final Map.Entry<String, List<FacesMessage>> entry : messages.entrySet()) {
93        for (final FacesMessage facesMessage : entry.getValue()) {
94          facesContext.addMessage(entry.getKey(), facesMessage);
95        }
96      }
97      facesContext.renderResponse();
98      if (LOG.isTraceEnabled()) {
99        LOG.trace("Restored viewRoot.getViewId() = \"{}\"", viewRoot.getViewId());
100       for (final Map.Entry<String, List<FacesMessage>> entry : messages.entrySet()) {
101         for (final FacesMessage message : entry.getValue()) {
102           LOG.trace("Restored message \"{}\" : \"{}\"", entry.getKey(), message);
103         }
104       }
105     }
106 
107   }
108 
109   public static void storeIncomingView(final FacesContext facesContext) {
110     final UIViewRoot viewRoot = facesContext.getViewRoot();
111     if (LOG.isTraceEnabled()) {
112       if (viewRoot != null) {
113         LOG.trace("incoming viewId = '{}'", viewRoot.getViewId());
114       } else {
115         LOG.trace("incoming viewRoot is null");
116       }
117     }
118     facesContext.getExternalContext().getRequestMap().put(AjaxNavigationState.VIEW_ROOT_KEY, viewRoot);
119   }
120 
121   public static boolean isNavigation(final FacesContext facesContext) {
122 
123     final UIViewRoot viewRoot = facesContext.getViewRoot();
124     if (viewRoot != null) {
125       if (LOG.isDebugEnabled()) {
126         LOG.debug("current viewId = '{}'", viewRoot.getViewId());
127       }
128     } else {
129       LOG.warn("current viewRoot is null");
130       return false;
131     }
132 
133     final Map<String, Object> requestMap = facesContext.getExternalContext().getRequestMap();
134     final UIViewRoot incomingViewRoot = (UIViewRoot) requestMap.get(VIEW_ROOT_KEY);
135     if (viewRoot != incomingViewRoot) {
136       if (LOG.isDebugEnabled()) {
137         LOG.debug("requesting full page reload because of navigation to {} from {}",
138             viewRoot.getViewId(), incomingViewRoot.getViewId());
139       }
140       return true;
141     }
142     return false;
143   }
144 
145   public static void beforeRestoreView(final FacesContext facesContext) {
146     if (facesContext.getExternalContext().getSessionMap().get(AjaxNavigationState.SESSION_KEY) != null) {
147       // restoreView phase and afterPhaseListener are executed even if renderResponse is set
148       // so we can't call navigationState.restoreView(...) here in before Phase
149       // set empty UIViewRoot to prevent executing restore state logic
150       facesContext.setViewRoot(new UIViewRoot());
151     }
152   }
153 
154   public static void afterRestoreView(final FacesContext facesContext) {
155     if (isViewExpiredExceptionThrown(facesContext)) {
156       try {
157         facesContext.getExceptionHandler().handle();
158       } catch (ViewExpiredException e) {
159         LOG.debug("Caught: " + e.getMessage(), e);
160         try {
161           final ExternalContext externalContext = facesContext.getExternalContext();
162           final String url = externalContext.getRequestContextPath()
163                        + externalContext.getRequestServletPath() + externalContext.getRequestPathInfo();
164           AjaxInternalUtils.redirect(facesContext, url);
165           facesContext.responseComplete();
166         } catch (IOException e1) {
167           LOG.error("Caught: " + e1.getMessage(), e);
168         }
169       }
170     }
171 
172     final ExternalContext externalContext = facesContext.getExternalContext();
173     if (externalContext.getSessionMap().get(AjaxNavigationState.SESSION_KEY) == null) {
174       storeIncomingView(facesContext);
175     } else {
176       final AjaxNavigationState navigationState
177           = (AjaxNavigationState) externalContext.getSessionMap().remove(AjaxNavigationState.SESSION_KEY);
178       navigationState.restoreView(facesContext);
179       LOG.trace("force render requested navigation view");
180     }
181   }
182 
183   private static boolean isViewExpiredExceptionThrown(FacesContext facesContext) {
184     final Iterator<ExceptionQueuedEvent> eventIterator
185         = facesContext.getExceptionHandler().getUnhandledExceptionQueuedEvents().iterator();
186     if (eventIterator.hasNext()) {
187       Throwable throwable = eventIterator.next().getContext().getException();
188       if (throwable instanceof ViewExpiredException) {
189         return true;
190       }
191     }
192     return false;
193   }
194 
195   public static void afterInvokeApplication(FacesContext facesContext) {
196 //    if (AjaxUtils.isAjaxRequest(facesContext) && isNavigation(facesContext)) {
197     if (false) {
198       try {
199         facesContext.getExternalContext().getSessionMap().put(SESSION_KEY, new AjaxNavigationState(facesContext));
200         AjaxInternalUtils.requestNavigationReload(facesContext);
201       } catch (IOException e) {
202         LOG.error("Caught: " + e.getMessage(), e);
203       }
204     }
205   }
206 }