2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

Coverage Report - org.apache.shale.view.faces.ViewPhaseListener
 
Classes in this File Line Coverage Branch Coverage Complexity
ViewPhaseListener
0% 
0% 
4.222
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to you under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 
 18  
 package org.apache.shale.view.faces;
 19  
 
 20  
 import java.io.IOException;
 21  
 import java.util.Iterator;
 22  
 import java.util.List;
 23  
 import java.util.Map;
 24  
 import javax.faces.context.ExternalContext;
 25  
 import javax.faces.context.FacesContext;
 26  
 import javax.faces.el.ValueBinding;
 27  
 
 28  
 import javax.faces.event.PhaseEvent;
 29  
 import javax.faces.event.PhaseId;
 30  
 import javax.faces.event.PhaseListener;
 31  
 
 32  
 import org.apache.commons.logging.Log;
 33  
 import org.apache.commons.logging.LogFactory;
 34  
 import org.apache.shale.view.ApplicationException;
 35  
 import org.apache.shale.view.Constants;
 36  
 import org.apache.shale.view.ExceptionHandler;
 37  
 import org.apache.shale.view.ViewController;
 38  
 
 39  
 /**
 40  
  * <p>{@link ViewPhaseListener} is a JavaServer Faces <code>PhaseListener</code>
 41  
  * that implements phase related functionality for the view controller
 42  
  * portion of Shale.</p>
 43  
  *
 44  
  * $Id: ViewPhaseListener.java 477032 2006-11-20 04:17:39Z gvanmatre $
 45  
  */
 46  
 
 47  0
 public class ViewPhaseListener implements PhaseListener {
 48  
 
 49  
 
 50  
     // -------------------------------------------------------- Static Variables
 51  
 
 52  
 
 53  
     /**
 54  
      * Serial version UID.
 55  
      */
 56  
     private static final long serialVersionUID = 2096731130324222021L;
 57  
 
 58  
 
 59  
     /**
 60  
      * <p>The <code>Log</code> instance for this class.</p>
 61  
      */
 62  0
     private static final Log log = LogFactory.getLog(ViewPhaseListener.class);
 63  
 
 64  
 
 65  
     /**
 66  
      * <p>HTTP status to report in the exception attributes we set up.</p>
 67  
      */
 68  
     private static final int HTTP_STATUS = 200;
 69  
 
 70  
 
 71  
     /**
 72  
      * <p>Request scope attribute under which the {@link PhaseId} for the
 73  
      * current phase is exposed.</p>
 74  
      */
 75  
     public static final String PHASE_ID = "org.apache.shale.view.PHASE_ID";
 76  
 
 77  
 
 78  
     // --------------------------------------------------- PhaseListener Methods
 79  
 
 80  
 
 81  
     /**
 82  
      * <p>Perform after-phase processing for the phase defined in the
 83  
      * specified event.</p>
 84  
      *
 85  
      * @param event <code>PhaseEvent</code> for the current event
 86  
      */
 87  
     public void afterPhase(PhaseEvent event) {
 88  
 
 89  0
         if (log.isTraceEnabled()) {
 90  0
             log.trace("afterPhase(" + event.getFacesContext()
 91  
                       + "," + event.getPhaseId() + ")");
 92  
         }
 93  
         
 94  0
         if (afterPhaseExceptionCheck(event)) {
 95  
             // dispatched to the target error page, stop further processing
 96  0
             return;
 97  
         }
 98  
 
 99  0
         PhaseId phaseId = event.getPhaseId();
 100  0
         if (PhaseId.RESTORE_VIEW.equals(phaseId)) {
 101  0
             afterRestoreView(event);
 102  0
         } else if (PhaseId.RENDER_RESPONSE.equals(phaseId)
 103  
                    || event.getFacesContext().getResponseComplete()) {
 104  0
             afterRenderResponse(event);
 105  
         }
 106  0
         event.getFacesContext().getExternalContext().getRequestMap().remove(PHASE_ID);
 107  
 
 108  0
     }
 109  
 
 110  
 
 111  
     /**
 112  
      * <p>Perform before-phase processing for the phase defined in the
 113  
      * specified event.</p>
 114  
      *
 115  
      * @param event <code>PhaseEvent</code> for the current event
 116  
      */
 117  
     public void beforePhase(PhaseEvent event) {
 118  
 
 119  0
         if (log.isTraceEnabled()) {
 120  0
             log.trace("beforePhase(" + event.getFacesContext()
 121  
                       + "," + event.getPhaseId() + ")");
 122  
         }
 123  0
         PhaseId phaseId = event.getPhaseId();
 124  0
         event.getFacesContext().getExternalContext().getRequestMap().put(PHASE_ID, phaseId);
 125  0
         if (PhaseId.RENDER_RESPONSE.equals(phaseId)) {
 126  0
             beforeRenderResponse(event);
 127  
         }
 128  
 
 129  0
     }
 130  
 
 131  
 
 132  
     /**
 133  
      * <p>Return <code>PhaseId.ANY_PHASE</code>, indicating our interest
 134  
      * in all phases of the request processing lifecycle.</p>
 135  
      */
 136  
     public PhaseId getPhaseId() {
 137  
 
 138  0
         return PhaseId.ANY_PHASE;
 139  
 
 140  
     }
 141  
 
 142  
 
 143  
     // --------------------------------------------------------- Private Methods
 144  
 
 145  
 
 146  
     /**
 147  
      * <p>If any exceptions have been accumulated, and the user has specified
 148  
      * a forwarding URL, forward to that URL instead of allowing rendering
 149  
      * to proceed.</p>
 150  
      *
 151  
      * @param event <code>PhaseEvent</code> for the current event
 152  
      * @return <code>true</code> if exceptions have been handled
 153  
      * and dispatched to the specified path
 154  
      */
 155  
     private boolean afterPhaseExceptionCheck(PhaseEvent event) {
 156  
 
 157  
         // Have we accumulated any exceptions during the current request?
 158  
         // Have we already logged the exception?
 159  0
         FacesContext context = event.getFacesContext();
 160  0
         ExternalContext econtext = context.getExternalContext();
 161  0
         List list = (List)
 162  
           econtext.getRequestMap().get(FacesConstants.EXCEPTIONS_LIST);
 163  0
         if (list == null
 164  
          || econtext.getRequestMap().get("javax.servlet.error.exception") != null) {
 165  0
             return false;
 166  
         }
 167  
 
 168  
         // Has the user specified a forwarding URL for handling exceptions?
 169  0
         String path =
 170  
           econtext.getInitParameter(Constants.EXCEPTION_DISPATCH_PATH);
 171  0
         if (path == null) {
 172  0
             return false;
 173  
         }
 174  
 
 175  
         // Forward control to the specified path instead of allowing
 176  
         // rendering to complete, while simulating container error handling
 177  
         try {
 178  
             // Set up request attributes reflecting the error conditions,
 179  
             // similar to what is passed to an error handler by the servlet
 180  
             // container (see Section 9.9.1 of the Servlet Specification)
 181  0
             ApplicationException exception = new ApplicationException(list);
 182  0
             Map map = econtext.getRequestMap();
 183  0
             map.put("javax.servlet.error.status_code", new Integer(HTTP_STATUS)); // Not an HTTP error
 184  0
             map.put("javax.servlet.error.exception_type", ApplicationException.class);
 185  0
             map.put("javax.servlet.error.message", exception.getMessage());
 186  0
             map.put("javax.servlet.error.exception", exception);
 187  0
             StringBuffer sb = new StringBuffer("");
 188  0
             if (econtext.getRequestServletPath() != null) {
 189  0
                 sb.append(econtext.getRequestServletPath());
 190  
             }
 191  0
             if (econtext.getRequestPathInfo() != null) {
 192  0
                 sb.append(econtext.getRequestPathInfo());
 193  
             }
 194  0
             map.put("javax.servlet.error.request_uri", sb.toString());
 195  0
             map.put("javax.servlet.error.servlet_name", "javax.faces.webapp.FacesServlet"); // Best we can do ...
 196  
             // Dispatch to the specified error handler
 197  0
             context.responseComplete();
 198  
             // force a destroy before dispatching to the error page
 199  0
             econtext.getRequestMap().remove(FacesConstants.VIEWS_INITIALIZED);
 200  0
             econtext.dispatch(path);
 201  
 
 202  0
         } catch (IOException e) {
 203  0
             handleException(context, e);
 204  0
         }
 205  
 
 206  0
         return true;
 207  
     }
 208  
 
 209  
 
 210  
     /**
 211  
      * <p>Call the <code>destroy()</code> method of the {@link ViewController}s
 212  
      * that have been registered during this request (if any).</p>
 213  
      *
 214  
      * @param event <code>PhaseEvent</code> for the current event
 215  
      */
 216  
     private void afterRenderResponse(PhaseEvent event) {
 217  
 
 218  0
         Map map = event.getFacesContext().getExternalContext().getRequestMap();
 219  0
         List list = (List) map.get(FacesConstants.VIEWS_INITIALIZED);
 220  0
         if (list == null) {
 221  0
             return;
 222  
         }
 223  
         //Iterator vcs = list.iterator();
 224  
         //while (vcs.hasNext()) {
 225  
         //    Object vc = vcs.next();
 226  
         //     viewControllerCallbacks(event.getFacesContext()).destroy(vc);
 227  
         //}
 228  
 
 229  0
         map.remove(FacesConstants.VIEWS_INITIALIZED);
 230  
 
 231  0
     }
 232  
 
 233  
 
 234  
     /**
 235  
      * <p>Call the <code>preprocess()</code> method of the {@link ViewController}
 236  
      * that has been restored, if this is a postback.</p>
 237  
      *
 238  
      * @param event <code>PhaseEvent</code> for the current event
 239  
      */
 240  
     private void afterRestoreView(PhaseEvent event) {
 241  
 
 242  0
         Map map = event.getFacesContext().getExternalContext().getRequestMap();
 243  0
         List list = (List) map.get(FacesConstants.VIEWS_INITIALIZED);
 244  0
         if (list == null) {
 245  0
             return;
 246  
         }
 247  0
         if (!event.getFacesContext().getExternalContext().getRequestMap().containsKey(FacesConstants.VIEW_POSTBACK)) {
 248  0
             return;
 249  
         }
 250  0
         Iterator vcs = list.iterator();
 251  0
         while (vcs.hasNext()) {
 252  0
             Object vc = vcs.next();
 253  
             try {
 254  0
                 getViewControllerCallbacks(event.getFacesContext()).preprocess(vc);
 255  0
             } catch (Exception e) {
 256  0
                 handleException(event.getFacesContext(), e);
 257  0
             }
 258  0
         }
 259  
 
 260  0
     }
 261  
 
 262  
 
 263  
 
 264  
     /**
 265  
      * <p>Call the <code>prerender()</code> method of the {@link ViewController}
 266  
      * for the view about to be rendered (if any).</p>
 267  
      *
 268  
      * @param event <code>PhaseEvent</code> for the current event
 269  
      */
 270  
     private void beforeRenderResponse(PhaseEvent event) {
 271  
 
 272  0
         Map map = event.getFacesContext().getExternalContext().getRequestMap();
 273  0
         String viewName = (String) map.get(FacesConstants.VIEW_NAME_RENDERED);
 274  0
         if (viewName == null) {
 275  0
             return;
 276  
         }
 277  0
         Object vc = map.get(viewName);
 278  0
         if (vc == null) {
 279  0
             return;
 280  
         }
 281  
         try {
 282  0
             getViewControllerCallbacks(event.getFacesContext()).prerender(vc);
 283  0
         } catch (Exception e) {
 284  0
             handleException(event.getFacesContext(), e);
 285  0
         }
 286  0
         map.remove(FacesConstants.VIEW_NAME_RENDERED);
 287  
 
 288  0
     }
 289  
 
 290  
 
 291  
     /**
 292  
      * <p>Return the {@link ViewControllerCallbacks} instance we
 293  
      * will use.</p>
 294  
      *
 295  
      * @param context <code>FacesContext</code> for the current request
 296  
      */
 297  
     private ViewControllerCallbacks getViewControllerCallbacks(FacesContext context) {
 298  
 
 299  0
         ValueBinding vb = context.getApplication().createValueBinding
 300  
           ("#{" + FacesConstants.VIEW_CALLBACKS + "}");
 301  0
         return (ViewControllerCallbacks) vb.getValue(context);
 302  
 
 303  
     }
 304  
 
 305  
 
 306  
     /**
 307  
      * <p>Handle the specified exception according to the strategy
 308  
      * defined by our current {@link ExceptionHandler}.</p>
 309  
      *
 310  
      * @param context FacesContext for the current request
 311  
      * @param exception Exception to be handled
 312  
      */
 313  
     private void handleException(FacesContext context, Exception exception) {
 314  
 
 315  0
         if (context == null) {
 316  0
             exception.printStackTrace(System.out);
 317  0
             return;
 318  
         }
 319  0
         ExceptionHandler handler = (ExceptionHandler)
 320  
           context.getApplication().getVariableResolver().resolveVariable
 321  
                 (context, Constants.EXCEPTION_HANDLER);
 322  0
         handler.handleException(exception);
 323  
 
 324  0
     }
 325  
 
 326  
 
 327  
 }