Coverage Report - org.apache.myfaces.application.ViewHandlerImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
ViewHandlerImpl
0%
0/162
0%
0/84
3.231
 
 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  
 package org.apache.myfaces.application;
 20  
 
 21  
 import java.io.IOException;
 22  
 import java.util.ArrayList;
 23  
 import java.util.Collection;
 24  
 import java.util.Collections;
 25  
 import java.util.HashMap;
 26  
 import java.util.Iterator;
 27  
 import java.util.List;
 28  
 import java.util.Locale;
 29  
 import java.util.Map;
 30  
 import java.util.Set;
 31  
 import java.util.concurrent.ConcurrentHashMap;
 32  
 import java.util.logging.Level;
 33  
 import java.util.logging.Logger;
 34  
 
 35  
 import javax.faces.FacesException;
 36  
 import javax.faces.FactoryFinder;
 37  
 import javax.faces.application.Application;
 38  
 import javax.faces.application.StateManager;
 39  
 import javax.faces.application.ViewHandler;
 40  
 import javax.faces.component.UIViewParameter;
 41  
 import javax.faces.component.UIViewRoot;
 42  
 import javax.faces.context.ExternalContext;
 43  
 import javax.faces.context.FacesContext;
 44  
 import javax.faces.render.RenderKitFactory;
 45  
 import javax.faces.render.ResponseStateManager;
 46  
 import javax.faces.view.ViewDeclarationLanguage;
 47  
 import javax.faces.view.ViewDeclarationLanguageFactory;
 48  
 import javax.faces.view.ViewMetadata;
 49  
 import javax.servlet.http.HttpServletResponse;
 50  
 
 51  
 import org.apache.myfaces.application.viewstate.StateCacheUtils;
 52  
 import org.apache.myfaces.shared.application.DefaultViewHandlerSupport;
 53  
 import org.apache.myfaces.shared.application.InvalidViewIdException;
 54  
 import org.apache.myfaces.shared.application.ViewHandlerSupport;
 55  
 import org.apache.myfaces.view.facelets.StateWriter;
 56  
 
 57  
 /**
 58  
  * JSF 2.0 ViewHandler implementation 
 59  
  *
 60  
  * @since 2.0
 61  
  */
 62  
 public class ViewHandlerImpl extends ViewHandler
 63  
 {
 64  
     //private static final Log log = LogFactory.getLog(ViewHandlerImpl.class);
 65  0
     private static final Logger log = Logger.getLogger(ViewHandlerImpl.class.getName());
 66  
     public static final String FORM_STATE_MARKER = "<!--@@JSF_FORM_STATE_MARKER@@-->";
 67  
     private ViewHandlerSupport _viewHandlerSupport;
 68  
     private ViewDeclarationLanguageFactory _vdlFactory;
 69  
     
 70  
     private Set<String> _protectedViewsSet;
 71  
     private Set<String> _unmodifiableProtectedViewsSet;
 72  
     
 73  
     /**
 74  
      * Gets the current ViewHandler via FacesContext.getApplication().getViewHandler().
 75  
      * We have to use this method to invoke any other specified ViewHandler-method
 76  
      * in the code, because direct access (this.method()) will cause problems if
 77  
      * the ViewHandler is wrapped.
 78  
      * @param facesContext
 79  
      * @return
 80  
      */
 81  
     public static ViewHandler getViewHandler(FacesContext facesContext)
 82  
     {
 83  0
         return facesContext.getApplication().getViewHandler();
 84  
     }
 85  
 
 86  
     public ViewHandlerImpl()
 87  0
     {
 88  0
         _protectedViewsSet = Collections.newSetFromMap(new ConcurrentHashMap<String,Boolean>());
 89  0
         _unmodifiableProtectedViewsSet = Collections.unmodifiableSet(_protectedViewsSet);
 90  0
         _vdlFactory = (ViewDeclarationLanguageFactory)
 91  
                 FactoryFinder.getFactory(FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY);
 92  0
         if (log.isLoggable(Level.FINEST))
 93  
         {
 94  0
             log.finest("New ViewHandler instance created");
 95  
         }
 96  0
     }
 97  
 
 98  
     @Override
 99  
     public String deriveViewId(FacesContext context, String input)
 100  
     {
 101  0
         if(input != null)
 102  
         {
 103  
             try
 104  
             {
 105  0
                 return getViewHandlerSupport(context).calculateAndCheckViewId(context, input);
 106  
             }
 107  0
             catch (InvalidViewIdException e)
 108  
             {
 109  0
                 sendSourceNotFound(context, e.getMessage());
 110  
             }
 111  
         }
 112  0
         return input;   // If the argument input is null, return null.
 113  
     }
 114  
     
 115  
     @Override
 116  
     public String deriveLogicalViewId(FacesContext context, String rawViewId)
 117  
     {
 118  0
         if(rawViewId != null)
 119  
         {
 120  
             try
 121  
             {
 122  0
                 return getViewHandlerSupport(context).calculateViewId(context, rawViewId);
 123  
             }
 124  0
             catch (InvalidViewIdException e)
 125  
             {
 126  0
                 sendSourceNotFound(context, e.getMessage());
 127  
             }
 128  
         }
 129  0
         return rawViewId;   // If the argument input is null, return null.
 130  
     }
 131  
 
 132  
     @Override
 133  
     public String getBookmarkableURL(FacesContext context, String viewId,
 134  
             Map<String, List<String>> parameters, boolean includeViewParams)
 135  
     {
 136  
         Map<String, List<String>> viewParameters;
 137  0
         if (includeViewParams)
 138  
         {
 139  0
             viewParameters = getViewParameterList(context, viewId, parameters);
 140  
         }
 141  
         else
 142  
         {
 143  0
             viewParameters = parameters;
 144  
         }
 145  
         
 146  
         // note that we cannot use this.getActionURL(), because this will
 147  
         // cause problems if the ViewHandler is wrapped
 148  0
         String actionEncodedViewId = getViewHandler(context).getActionURL(context, viewId);
 149  
         
 150  0
         ExternalContext externalContext = context.getExternalContext();
 151  0
         String bookmarkEncodedURL = externalContext.encodeBookmarkableURL(actionEncodedViewId, viewParameters);
 152  0
         return externalContext.encodeActionURL(bookmarkEncodedURL);
 153  
     }
 154  
 
 155  
     @Override
 156  
     public String getRedirectURL(FacesContext context, String viewId,
 157  
             Map<String, List<String>> parameters, boolean includeViewParams)
 158  
     {
 159  
         Map<String, List<String>> viewParameters;
 160  0
         if (includeViewParams)
 161  
         {
 162  0
             viewParameters = getViewParameterList(context, viewId, parameters);
 163  
         }
 164  
         else
 165  
         {
 166  0
             viewParameters = parameters;
 167  
         }
 168  
         
 169  
         // note that we cannot use this.getActionURL(), because this will
 170  
         // cause problems if the ViewHandler is wrapped
 171  0
         String actionEncodedViewId = getViewHandler(context).getActionURL(context, viewId);
 172  
         
 173  0
         ExternalContext externalContext = context.getExternalContext();
 174  0
         String redirectEncodedURL = externalContext.encodeRedirectURL(actionEncodedViewId, viewParameters);
 175  0
         return externalContext.encodeActionURL(redirectEncodedURL);
 176  
     }
 177  
 
 178  
     @Override
 179  
     public ViewDeclarationLanguage getViewDeclarationLanguage(
 180  
             FacesContext context, String viewId)
 181  
     {
 182  
         // return a suitable ViewDeclarationLanguage implementation for the given viewId
 183  0
         return _vdlFactory.getViewDeclarationLanguage(viewId);
 184  
     }
 185  
 
 186  
     @Override
 187  
     public void initView(FacesContext context) throws FacesException
 188  
     {
 189  0
         if(context.getExternalContext().getRequestCharacterEncoding() == null)
 190  
         {
 191  0
             super.initView(context);    
 192  
         }
 193  0
     }
 194  
 
 195  
     /**
 196  
      * Get the locales specified as acceptable by the original request, compare them to the
 197  
      * locales supported by this Application and return the best match.
 198  
      */
 199  
     @Override
 200  
     public Locale calculateLocale(FacesContext facesContext)
 201  
     {
 202  0
         Application application = facesContext.getApplication();
 203  0
         for (Iterator<Locale> requestLocales = facesContext.getExternalContext().getRequestLocales(); requestLocales
 204  0
                 .hasNext();)
 205  
         {
 206  0
             Locale requestLocale = requestLocales.next();
 207  0
             for (Iterator<Locale> supportedLocales = application.getSupportedLocales(); supportedLocales.hasNext();)
 208  
             {
 209  0
                 Locale supportedLocale = supportedLocales.next();
 210  
                 // higher priority to a language match over an exact match
 211  
                 // that occurs further down (see JSTL Reference 1.0 8.3.1)
 212  0
                 if (requestLocale.getLanguage().equals(supportedLocale.getLanguage())
 213  
                         && (supportedLocale.getCountry() == null || supportedLocale.getCountry().length() == 0))
 214  
                 {
 215  0
                     return supportedLocale;
 216  
                 }
 217  0
                 else if (supportedLocale.equals(requestLocale))
 218  
                 {
 219  0
                     return supportedLocale;
 220  
                 }
 221  0
             }
 222  0
         }
 223  
 
 224  0
         Locale defaultLocale = application.getDefaultLocale();
 225  0
         return defaultLocale != null ? defaultLocale : Locale.getDefault();
 226  
     }
 227  
 
 228  
     @Override
 229  
     public String calculateRenderKitId(FacesContext facesContext)
 230  
     {
 231  0
         Object renderKitId = facesContext.getExternalContext().getRequestMap().get(
 232  
                 ResponseStateManager.RENDER_KIT_ID_PARAM);
 233  0
         if (renderKitId == null)
 234  
         {
 235  0
             renderKitId = facesContext.getApplication().getDefaultRenderKitId();
 236  
         }
 237  0
         if (renderKitId == null)
 238  
         {
 239  0
             renderKitId = RenderKitFactory.HTML_BASIC_RENDER_KIT;
 240  
         }
 241  0
         return renderKitId.toString();
 242  
     }
 243  
     
 244  
     @Override
 245  
     public UIViewRoot createView(FacesContext context, String viewId)
 246  
     {
 247  0
        checkNull(context, "facesContext");
 248  0
        String calculatedViewId = getViewHandlerSupport(context).calculateViewId(context, viewId);
 249  
        
 250  
        // we cannot use this.getVDL() directly (see getViewHandler())
 251  
        //return getViewHandler(context)
 252  
        //        .getViewDeclarationLanguage(context, calculatedViewId)
 253  
        //            .createView(context, calculatedViewId);
 254  
        // -= Leonardo Uribe =- Temporally reverted by TCK issues.
 255  0
        ViewDeclarationLanguage vdl = getViewDeclarationLanguage(context,calculatedViewId);
 256  0
        if (vdl == null)
 257  
        {
 258  
            // If there is no VDL that can handle the view, throw 404 response.
 259  0
            sendSourceNotFound(context, viewId);
 260  0
            return null;
 261  
        }
 262  0
        return vdl.createView(context,calculatedViewId);
 263  
     }
 264  
 
 265  
     @Override
 266  
     public String getActionURL(FacesContext context, String viewId)
 267  
     {
 268  0
         checkNull(context, "facesContext");
 269  0
         checkNull(viewId, "viewId");
 270  0
         return getViewHandlerSupport(context).calculateActionURL(context, viewId);
 271  
     }
 272  
 
 273  
     @Override
 274  
     public String getResourceURL(FacesContext facesContext, String path)
 275  
     {
 276  0
         checkNull(facesContext, "facesContext");
 277  0
         checkNull(path, "path");
 278  0
         if (path.length() > 0 && path.charAt(0) == '/')
 279  
         {
 280  0
             String contextPath = facesContext.getExternalContext().getRequestContextPath();
 281  0
             if (contextPath == null)
 282  
             {
 283  0
                 return path;
 284  
             }
 285  0
             else if (contextPath.length() == 1 && contextPath.charAt(0) == '/')
 286  
             {
 287  
                 // If the context path is root, it is not necessary to append it, otherwise
 288  
                 // and extra '/' will be set.
 289  0
                 return path;
 290  
             }
 291  
             else
 292  
             {
 293  0
                 return  contextPath + path;
 294  
             }
 295  
         }
 296  0
         return path;
 297  
 
 298  
     }
 299  
 
 300  
     @Override
 301  
     public void renderView(FacesContext context, UIViewRoot viewToRender)
 302  
             throws IOException, FacesException
 303  
     {
 304  
 
 305  0
         checkNull(context, "context");
 306  0
         checkNull(viewToRender, "viewToRender");
 307  
 
 308  
         // we cannot use this.getVDL() directly (see getViewHandler())
 309  
         //String viewId = viewToRender.getViewId();
 310  
         //getViewHandler(context).getViewDeclarationLanguage(context, viewId)
 311  
         //        .renderView(context, viewToRender);
 312  
         // -= Leonardo Uribe =- Temporally reverted by TCK issues.
 313  0
         getViewDeclarationLanguage(context,viewToRender.getViewId()).renderView(context, viewToRender);
 314  0
     }
 315  
 
 316  
     @Override
 317  
     public UIViewRoot restoreView(FacesContext context, String viewId)
 318  
     {
 319  0
         checkNull(context, "context");
 320  
     
 321  0
         String calculatedViewId = getViewHandlerSupport(context).calculateViewId(context, viewId);
 322  
         
 323  
         // we cannot use this.getVDL() directly (see getViewHandler())
 324  
         //return getViewHandler(context)
 325  
         //        .getViewDeclarationLanguage(context,calculatedViewId)
 326  
         //            .restoreView(context, calculatedViewId);
 327  
         // -= Leonardo Uribe =- Temporally reverted by TCK issues.
 328  0
         ViewDeclarationLanguage vdl = getViewDeclarationLanguage(context,calculatedViewId);
 329  0
         if (vdl == null)
 330  
         {
 331  
             // If there is no VDL that can handle the view, throw 404 response.
 332  0
             sendSourceNotFound(context, viewId);
 333  0
             return null;
 334  
             
 335  
         }
 336  0
         return vdl.restoreView(context, calculatedViewId); 
 337  
     }
 338  
     
 339  
     @Override
 340  
     public void writeState(FacesContext context) throws IOException
 341  
     {
 342  0
         checkNull(context, "context");
 343  
 
 344  0
         if(context.getPartialViewContext().isAjaxRequest())
 345  
         {
 346  0
             return;
 347  
         }
 348  
 
 349  0
         ResponseStateManager responseStateManager = context.getRenderKit().getResponseStateManager();
 350  
         
 351  0
         setWritingState(context, responseStateManager);
 352  
 
 353  0
         StateManager stateManager = context.getApplication().getStateManager();
 354  
         
 355  
         // By the spec, it is necessary to use a writer to write FORM_STATE_MARKER, 
 356  
         // after the view is rendered, to preserve changes done on the component tree
 357  
         // on rendering time. But if server side state saving is used, this is not 
 358  
         // really necessary, because a token could be used and after the view is
 359  
         // rendered, a simple call to StateManager.saveState() could do the trick.
 360  
         // The code below check if we are using MyFacesResponseStateManager and if
 361  
         // that so, check if the current one support the trick.
 362  0
         if (StateCacheUtils.isMyFacesResponseStateManager(responseStateManager))
 363  
         {
 364  0
             if (StateCacheUtils.getMyFacesResponseStateManager(responseStateManager).
 365  
                     isWriteStateAfterRenderViewRequired(context))
 366  
             {
 367  
                 // Only write state marker if javascript view state is disabled
 368  0
                 context.getResponseWriter().write(FORM_STATE_MARKER);
 369  
             }
 370  
             else
 371  
             {
 372  0
                 stateManager.writeState(context, new Object[2]);
 373  
             }
 374  
         }
 375  
         else
 376  
         {
 377  
             // Only write state marker if javascript view state is disabled
 378  0
             context.getResponseWriter().write(FORM_STATE_MARKER);
 379  
         }
 380  0
     }
 381  
 
 382  
     @Override
 383  
     public void addProtectedView(String urlPattern)
 384  
     {
 385  0
         _protectedViewsSet.add(urlPattern);
 386  0
     }
 387  
 
 388  
     @Override
 389  
     public boolean removeProtectedView(String urlPattern)
 390  
     {
 391  0
         return _protectedViewsSet.remove(urlPattern);
 392  
     }
 393  
 
 394  
     @Override
 395  
     public Set<String> getProtectedViewsUnmodifiable()
 396  
     {
 397  0
         return _unmodifiableProtectedViewsSet;
 398  
     }
 399  
     
 400  
     private void setWritingState(FacesContext context, ResponseStateManager rsm)
 401  
     {
 402  
         // Facelets specific hack:
 403  
         // Tell the StateWriter that we're about to write state
 404  0
         StateWriter stateWriter = StateWriter.getCurrentInstance(context);
 405  0
         if (stateWriter != null)
 406  
         {
 407  
             // Write the STATE_KEY out. Unfortunately, this will
 408  
             // be wasteful for pure server-side state managers where nothing
 409  
             // is actually written into the output, but this cannot
 410  
             // programatically be discovered
 411  
             // -= Leonardo Uribe =- On MyFacesResponseStateManager was added
 412  
             // some methods to discover it programatically.
 413  0
             if (StateCacheUtils.isMyFacesResponseStateManager(rsm))
 414  
             {
 415  0
                 if (StateCacheUtils.getMyFacesResponseStateManager(rsm).isWriteStateAfterRenderViewRequired(context))
 416  
                 {
 417  0
                     stateWriter.writingState();
 418  
                 }
 419  
                 else
 420  
                 {
 421  0
                     stateWriter.writingStateWithoutWrapper();
 422  
                 }
 423  
             }
 424  
             else
 425  
             {
 426  0
                 stateWriter.writingState();
 427  
             }
 428  
             
 429  
             
 430  
         }
 431  
         //else
 432  
         //{
 433  
             //we're in a JSP, let the JSPStatemanager know that we need to actually write the state
 434  
         //}        
 435  0
     }
 436  
     
 437  
     private Map<String, List<String>> getViewParameterList(FacesContext context,
 438  
             String viewId, Map<String, List<String>> parametersFromArg)
 439  
     {
 440  0
         UIViewRoot viewRoot = context.getViewRoot();
 441  0
         String currentViewId = viewRoot.getViewId();
 442  0
         Collection<UIViewParameter> toViewParams = null;
 443  0
         Collection<UIViewParameter> currentViewParams = ViewMetadata.getViewParameters(viewRoot);
 444  
 
 445  0
         if (currentViewId.equals(viewId))
 446  
         {
 447  0
             toViewParams = currentViewParams;
 448  
         }
 449  
         else
 450  
         {
 451  0
             String calculatedViewId = getViewHandlerSupport(context).calculateViewId(context, viewId);  
 452  
             // we cannot use this.getVDL() directly (see getViewHandler())
 453  
             //ViewDeclarationLanguage vdl = getViewHandler(context).
 454  
             //        getViewDeclarationLanguage(context, calculatedViewId);
 455  
             // -= Leonardo Uribe =- Temporally reverted by TCK issues.
 456  0
             ViewDeclarationLanguage vdl = getViewDeclarationLanguage(context,calculatedViewId);
 457  0
             ViewMetadata viewMetadata = vdl.getViewMetadata(context, viewId);
 458  
             // getViewMetadata() returns null on JSP
 459  0
             if (viewMetadata != null)
 460  
             {
 461  0
                 UIViewRoot viewFromMetaData = viewMetadata.createMetadataView(context);
 462  0
                 toViewParams = ViewMetadata.getViewParameters(viewFromMetaData);
 463  
             }
 464  
         }
 465  
 
 466  0
         if (toViewParams == null || toViewParams.isEmpty())
 467  
         {
 468  0
             return parametersFromArg;
 469  
         }
 470  
         
 471  
         // we need to use a custom Map to add the view parameters,
 472  
         // otherwise the current value of the view parameter will be added to
 473  
         // the navigation case as a static (!!!) parameter, thus the value
 474  
         // won't be updated on any following request
 475  
         // (Note that parametersFromArg is the Map from the NavigationCase)
 476  
         // Also note that we don't have to copy the Lists, because they won't be changed
 477  0
         Map<String, List<String>> parameters = new HashMap<String, List<String>>();
 478  0
         parameters.putAll(parametersFromArg);
 479  
 
 480  0
         for (UIViewParameter viewParameter : toViewParams)
 481  
         {
 482  0
             if (!parameters.containsKey(viewParameter.getName()))
 483  
             {
 484  0
                 String parameterValue = viewParameter.getStringValueFromModel(context);
 485  0
                 if (parameterValue == null)
 486  
                 {
 487  0
                     if(currentViewId.equals(viewId))
 488  
                     {
 489  0
                         parameterValue = viewParameter.getStringValue(context);
 490  
                     }
 491  
                     else
 492  
                     {
 493  0
                         if (viewParameter.getName() != null)
 494  
                         {
 495  0
                             for (UIViewParameter curParam : currentViewParams)
 496  
                             {
 497  0
                                 if (viewParameter.getName().equals(curParam.getName())) 
 498  
                                 {
 499  0
                                     parameterValue = curParam.getStringValue(context);
 500  0
                                     break;
 501  
                                 }
 502  0
                             }
 503  
                         }
 504  
                     }
 505  
                 }
 506  
 
 507  0
                 if (parameterValue != null)
 508  
                 {
 509  
                     // since we have checked !parameters.containsKey(viewParameter.getName())
 510  
                     // here already, the parameters Map will never contain a List under the
 511  
                     // key viewParameter.getName(), thus we do not have to check it here (again).
 512  0
                     List<String> parameterValueList = new ArrayList<String>();
 513  0
                     parameterValueList.add(parameterValue);
 514  0
                     parameters.put(viewParameter.getName(), parameterValueList);
 515  
                 }
 516  
             }
 517  0
         }        
 518  0
         return parameters;
 519  
     }
 520  
     
 521  
     private void checkNull(final Object o, final String param)
 522  
     {
 523  0
         if (o == null)
 524  
         {
 525  0
             throw new NullPointerException(param + " can not be null.");
 526  
         }
 527  0
     }
 528  
     
 529  
     private void sendSourceNotFound(FacesContext context, String message)
 530  
     {
 531  0
         HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
 532  
         try
 533  
         {
 534  0
             context.responseComplete();
 535  0
             response.sendError(HttpServletResponse.SC_NOT_FOUND, message);
 536  
         }
 537  0
         catch (IOException ioe)
 538  
         {
 539  0
             throw new FacesException(ioe);
 540  0
         }
 541  0
     }
 542  
     
 543  
     public void setViewHandlerSupport(ViewHandlerSupport viewHandlerSupport)
 544  
     {
 545  0
         _viewHandlerSupport = viewHandlerSupport;
 546  0
     }    
 547  
     
 548  
     protected ViewHandlerSupport getViewHandlerSupport()
 549  
     {
 550  0
         return getViewHandlerSupport(FacesContext.getCurrentInstance());
 551  
     }
 552  
 
 553  
     protected ViewHandlerSupport getViewHandlerSupport(FacesContext context)
 554  
     {
 555  0
         if (_viewHandlerSupport == null)
 556  
         {
 557  0
             _viewHandlerSupport = new DefaultViewHandlerSupport(context);
 558  
         }
 559  0
         return _viewHandlerSupport;
 560  
     }
 561  
 }