Coverage Report - org.apache.myfaces.shared.view.JspViewDeclarationLanguageBase
 
Classes in this File Line Coverage Branch Coverage Complexity
JspViewDeclarationLanguageBase
0%
0/124
0%
0/56
3.059
 
 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.shared.view;
 20  
 
 21  
 import java.beans.BeanInfo;
 22  
 import java.io.IOException;
 23  
 import java.io.StringWriter;
 24  
 import java.io.Writer;
 25  
 import java.util.logging.Level;
 26  
 import java.util.logging.Logger;
 27  
 
 28  
 import javax.faces.FactoryFinder;
 29  
 import javax.faces.application.Resource;
 30  
 import javax.faces.application.StateManager;
 31  
 import javax.faces.application.ViewHandler;
 32  
 import javax.faces.component.UIViewRoot;
 33  
 import javax.faces.context.ExternalContext;
 34  
 import javax.faces.context.FacesContext;
 35  
 import javax.faces.context.ResponseWriter;
 36  
 import javax.faces.render.RenderKit;
 37  
 import javax.faces.render.RenderKitFactory;
 38  
 import javax.faces.view.StateManagementStrategy;
 39  
 import javax.faces.view.ViewDeclarationLanguage;
 40  
 import javax.faces.view.ViewMetadata;
 41  
 import javax.servlet.ServletResponse;
 42  
 import javax.servlet.ServletResponseWrapper;
 43  
 import javax.servlet.http.HttpServletResponse;
 44  
 
 45  
 import org.apache.myfaces.shared.application.DefaultViewHandlerSupport;
 46  
 import org.apache.myfaces.shared.application.ViewHandlerSupport;
 47  
 import org.apache.myfaces.shared.config.MyfacesConfig;
 48  
 
 49  
 
 50  0
 public abstract class JspViewDeclarationLanguageBase extends ViewDeclarationLanguageBase
 51  
 {
 52  0
   private static final Logger log = Logger.getLogger(JspViewDeclarationLanguageBase.class.getName());
 53  
   
 54  
   private static final String FORM_STATE_MARKER = "<!--@@JSF_FORM_STATE_MARKER@@-->";
 55  0
   private static final String AFTER_VIEW_TAG_CONTENT_PARAM = JspViewDeclarationLanguageBase.class
 56  
               + ".AFTER_VIEW_TAG_CONTENT";
 57  0
   private static final int FORM_STATE_MARKER_LEN = FORM_STATE_MARKER.length();
 58  
 
 59  
   private ViewHandlerSupport _cachedViewHandlerSupport;
 60  
   
 61  
   @Override
 62  
   public String getId()
 63  
   {
 64  0
       return ViewDeclarationLanguage.JSP_VIEW_DECLARATION_LANGUAGE_ID;
 65  
   }
 66  
   
 67  
   @Override
 68  
   public void buildView(FacesContext context, UIViewRoot view) throws IOException
 69  
   {
 70  
       // memorize that buildView() has been called for this view
 71  0
       setViewBuilt(context, view);
 72  
       
 73  0
       if (context.getPartialViewContext().isPartialRequest())
 74  
       {
 75  
           // try to get (or create) a ResponseSwitch and turn off the output
 76  0
           Object origResponse = context.getExternalContext().getResponse();
 77  0
           ResponseSwitch responseSwitch = getResponseSwitch(origResponse);
 78  0
           if (responseSwitch == null)
 79  
           {
 80  
               // no ResponseSwitch installed yet - create one 
 81  0
               responseSwitch = createResponseSwitch(origResponse);
 82  0
               if (responseSwitch != null)
 83  
               {
 84  
                   // install the ResponseSwitch
 85  0
                   context.getExternalContext().setResponse(responseSwitch);
 86  
               }
 87  
           }
 88  0
           if (responseSwitch != null)
 89  
           {
 90  
               // turn the output off
 91  0
               responseSwitch.setEnabled(false);
 92  
           }
 93  
       }
 94  0
   }
 95  
   
 96  
   /**
 97  
    * {@inheritDoc}
 98  
    */
 99  
   @Override
 100  
   public BeanInfo getComponentMetadata(FacesContext context, Resource componentResource)
 101  
   {
 102  0
       throw new UnsupportedOperationException();
 103  
   }
 104  
   /**
 105  
    * {@inheritDoc}
 106  
    */
 107  
   @Override
 108  
   public Resource getScriptComponentResource(FacesContext context, Resource componentResource)
 109  
   {
 110  0
       throw new UnsupportedOperationException();
 111  
   }
 112  
   /**
 113  
    * {@inheritDoc}
 114  
    */
 115  
   @Override
 116  
   public void renderView(FacesContext context, UIViewRoot view) throws IOException
 117  
   {
 118  
       //Try not to use native objects in this class.  Both MyFaces and the bridge
 119  
       //provide implementations of buildView but they do not override this class.
 120  0
       checkNull(context, "context");
 121  0
       checkNull(view, "view");
 122  
       
 123  
       // do not render the view if the rendered attribute for the view is false
 124  0
       if (!view.isRendered())
 125  
       {
 126  0
           if (log.isLoggable(Level.FINEST))
 127  
           {
 128  0
               log.finest("View is not rendered");
 129  
           }
 130  0
           return;
 131  
       }
 132  
       
 133  
       // Check if the current view has already been built via VDL.buildView()
 134  
       // and if not, build it from here. This is necessary because legacy ViewHandler
 135  
       // implementations return null on getViewDeclarationLanguage() and thus
 136  
       // VDL.buildView() is never called. Furthermore, before JSF 2.0 introduced 
 137  
       // the VDLs, the code that built the view was in ViewHandler.renderView().
 138  0
       if (!isViewBuilt(context, view))
 139  
       {
 140  0
           buildView(context, view);
 141  
       }
 142  
   
 143  0
       ExternalContext externalContext = context.getExternalContext();
 144  
   
 145  0
       String viewId = context.getViewRoot().getViewId();
 146  
   
 147  0
       if (log.isLoggable(Level.FINEST))
 148  
       {
 149  0
           log.finest("Rendering JSP view: " + viewId);
 150  
       }
 151  
   
 152  
   
 153  
       // handle character encoding as of section 2.5.2.2 of JSF 1.1
 154  0
       if(null != externalContext.getSession(false))
 155  
       {
 156  0
         externalContext.getSessionMap().put(ViewHandler.CHARACTER_ENCODING_KEY, 
 157  
                 externalContext.getResponseCharacterEncoding());
 158  
       }
 159  
   
 160  
       // render the view in this method (since JSF 1.2)
 161  0
       RenderKitFactory renderFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
 162  0
       RenderKit renderKit = renderFactory.getRenderKit(context, view.getRenderKitId());
 163  
   
 164  0
       ResponseWriter responseWriter = context.getResponseWriter();
 165  0
       if (responseWriter == null)
 166  
       {
 167  0
           responseWriter = renderKit.createResponseWriter(externalContext.getResponseOutputWriter(), 
 168  
                   null, externalContext.getRequestCharacterEncoding());
 169  0
           context.setResponseWriter(responseWriter);
 170  
       }
 171  
       
 172  
       // try to enable the ResponseSwitch again (disabled in buildView())
 173  0
       Object response = context.getExternalContext().getResponse();
 174  0
       ResponseSwitch responseSwitch = getResponseSwitch(response);
 175  0
       if (responseSwitch != null)
 176  
       {
 177  0
           responseSwitch.setEnabled(true);
 178  
       }
 179  
   
 180  0
       ResponseWriter oldResponseWriter = responseWriter;
 181  0
       StringWriter stateAwareWriter = null;
 182  
       
 183  0
       StateManager stateManager = context.getApplication().getStateManager();
 184  0
       boolean viewStateAlreadyEncoded = isViewStateAlreadyEncoded(context);
 185  
       
 186  0
       if (!viewStateAlreadyEncoded)
 187  
       {
 188  
         // we will need to parse the reponse and replace the view_state token with the actual state
 189  0
         stateAwareWriter = new StringWriter();
 190  
   
 191  
         // Create a new response-writer using as an underlying writer the stateAwareWriter
 192  
         // Effectively, all output will be buffered in the stateAwareWriter so that later
 193  
         // this writer can replace the state-markers with the actual state.
 194  0
         responseWriter = oldResponseWriter.cloneWithWriter(stateAwareWriter);
 195  0
         context.setResponseWriter(responseWriter);
 196  
       }
 197  
   
 198  
       try
 199  
       {
 200  0
         if (!actuallyRenderView(context, view))
 201  
         {
 202  
           return;
 203  
         }
 204  
       }
 205  
       finally
 206  
       {
 207  0
         if(oldResponseWriter != null)
 208  
         {
 209  0
             context.setResponseWriter(oldResponseWriter);    
 210  
         }
 211  
       }
 212  
   
 213  0
       if (!viewStateAlreadyEncoded)
 214  
       {
 215  
         // parse the response and replace the token wit the state
 216  0
         flushBufferToWriter(stateAwareWriter.getBuffer(), externalContext.getResponseOutputWriter());
 217  
       }
 218  
       else
 219  
       {
 220  0
         stateManager.saveView(context);
 221  
       }
 222  
       
 223  
       // now disable the ResponseSwitch again
 224  0
       if (responseSwitch != null)
 225  
       {
 226  0
           responseSwitch.setEnabled(false);
 227  
       }
 228  
   
 229  
       // Final step - we output any content in the wrappedResponse response from above to the response,
 230  
       // removing the wrappedResponse response from the request, we don't need it anymore
 231  0
       ViewResponseWrapper afterViewTagResponse = (ViewResponseWrapper) externalContext.getRequestMap()
 232  
               .get(AFTER_VIEW_TAG_CONTENT_PARAM);
 233  0
       externalContext.getRequestMap().remove(AFTER_VIEW_TAG_CONTENT_PARAM);
 234  
       
 235  
       // afterViewTagResponse is null if the current request is a partial request
 236  0
       if (afterViewTagResponse != null)
 237  
       {
 238  0
           afterViewTagResponse.flushToWriter(externalContext.getResponseOutputWriter(), 
 239  
                   externalContext.getResponseCharacterEncoding());
 240  
       }
 241  
   
 242  
       //TODO sobryan: Is this right?
 243  0
       context.getResponseWriter().flush();
 244  0
   }
 245  
   /**
 246  
    * {@inheritDoc}
 247  
    */
 248  
   @Override
 249  
   public ViewMetadata getViewMetadata(FacesContext context, String viewId)
 250  
   {
 251  
       // Not necessary given that this method always returns null, but staying true to
 252  
       // the spec.
 253  
   
 254  0
       checkNull(context, "context");
 255  
       //checkNull(viewId, "viewId");
 256  
   
 257  
       // JSP impl must return null.
 258  
   
 259  0
       return null;
 260  
   }
 261  
   
 262  
   protected boolean isViewStateAlreadyEncoded(FacesContext context)
 263  
   {
 264  0
     if (MyfacesConfig.getCurrentInstance(context.getExternalContext()).isMyfacesImplAvailable())
 265  
     {
 266  
       // In MyFaces the viewState key is already encoded is server side state saving is being used
 267  0
       return !context.getApplication().getStateManager().isSavingStateInClient(context);
 268  
     }
 269  
     else
 270  
     {
 271  0
       return false;
 272  
     }
 273  
   }
 274  
   
 275  
   protected void setAfterViewTagResponseWrapper(ExternalContext ec, ViewResponseWrapper wrapper)
 276  
   {
 277  0
     ec.getRequestMap().put(AFTER_VIEW_TAG_CONTENT_PARAM, wrapper);
 278  0
   }
 279  
   
 280  
   protected void flushBufferToWriter(StringBuffer buff, Writer writer) throws IOException
 281  
   {
 282  0
     FacesContext facesContext = FacesContext.getCurrentInstance();
 283  0
     StateManager stateManager = facesContext.getApplication().getStateManager();
 284  
 
 285  0
     StringWriter stateWriter = new StringWriter();
 286  0
     ResponseWriter realWriter = facesContext.getResponseWriter();
 287  0
     facesContext.setResponseWriter(realWriter.cloneWithWriter(stateWriter));
 288  
 
 289  0
     Object serializedView = stateManager.saveView(facesContext);
 290  
 
 291  0
     stateManager.writeState(facesContext, serializedView);
 292  0
     facesContext.setResponseWriter(realWriter);
 293  
 
 294  0
     String state = stateWriter.getBuffer().toString();
 295  
 
 296  
     // State markers must be replaced
 297  0
     int lastFormMarkerPos = 0;
 298  0
     int formMarkerPos = 0;
 299  
     // Find all state markers and write out actual state instead
 300  0
     while ((formMarkerPos = buff.indexOf(JspViewDeclarationLanguageBase.FORM_STATE_MARKER, formMarkerPos)) > -1)
 301  
     {
 302  
       // Write content before state marker
 303  0
       writePartialBuffer(buff, lastFormMarkerPos, formMarkerPos, writer);
 304  
       // Write state and move position in buffer after marker
 305  0
       writer.write(state);
 306  0
       formMarkerPos += JspViewDeclarationLanguageBase.FORM_STATE_MARKER_LEN;
 307  0
       lastFormMarkerPos = formMarkerPos;
 308  
     }
 309  
 
 310  
     // Write content after last state marker
 311  0
     if (lastFormMarkerPos < buff.length())
 312  
     {
 313  0
       writePartialBuffer(buff, lastFormMarkerPos, buff.length(), writer);
 314  
     }
 315  0
   }
 316  
   
 317  
   protected void writePartialBuffer(StringBuffer contentBuffer, int beginIndex, 
 318  
           int endIndex, Writer writer) throws IOException
 319  
   {
 320  0
     int index = beginIndex;
 321  0
     int bufferSize = 2048;
 322  0
     char[] bufToWrite = new char[bufferSize];
 323  
 
 324  0
     while (index < endIndex)
 325  
     {
 326  0
       int maxSize = Math.min(bufferSize, endIndex - index);
 327  
 
 328  0
       contentBuffer.getChars(index, index + maxSize, bufToWrite, 0);
 329  0
       writer.write(bufToWrite, 0, maxSize);
 330  
 
 331  0
       index += bufferSize;
 332  0
     }
 333  0
   }
 334  
 
 335  
   /**
 336  
    * Render the view now - properly setting and resetting the response writer
 337  
    * [MF] Modified to return a boolean so subclass that delegates can determine
 338  
    * whether the rendering succeeded or not. TRUE means success.
 339  
    */
 340  
   protected boolean actuallyRenderView(FacesContext facesContext, UIViewRoot viewToRender)
 341  
       throws IOException
 342  
   {
 343  
       // Set the new ResponseWriter into the FacesContext, saving the old one aside.
 344  0
       ResponseWriter responseWriter = facesContext.getResponseWriter();
 345  
   
 346  
       // Now we actually render the document
 347  
       // Call startDocument() on the ResponseWriter.
 348  0
       responseWriter.startDocument();
 349  
   
 350  
       // Call encodeAll() on the UIViewRoot
 351  0
       viewToRender.encodeAll(facesContext);
 352  
   
 353  
       // Call endDocument() on the ResponseWriter
 354  0
       responseWriter.endDocument();
 355  
   
 356  0
       responseWriter.flush();
 357  
       
 358  
       // rendered successfully -- forge ahead
 359  0
       return true;
 360  
   }
 361  
   
 362  
   @Override
 363  
   public StateManagementStrategy getStateManagementStrategy(FacesContext context, String viewId)
 364  
   {
 365  0
       return null;
 366  
   }
 367  
 
 368  
   @Override
 369  
   protected String calculateViewId(FacesContext context, String viewId)
 370  
   {
 371  0
       if (_cachedViewHandlerSupport == null)
 372  
       {
 373  0
           _cachedViewHandlerSupport = new DefaultViewHandlerSupport();
 374  
       }
 375  
   
 376  0
       return _cachedViewHandlerSupport.calculateViewId(context, viewId);
 377  
   }
 378  
   
 379  
   /**
 380  
    * Returns true if the given UIViewRoot has already been built via VDL.buildView().
 381  
    * This is necessary because legacy ViewHandler implementations return null on 
 382  
    * getViewDeclarationLanguage() and thus VDL.buildView() is never called. 
 383  
    * So we have to check this in renderView() and, if it is false, we have to
 384  
    * call buildView() manually before the rendering.
 385  
    *  
 386  
    * @param facesContext
 387  
    * @param view
 388  
    * @return
 389  
    */
 390  
   protected boolean isViewBuilt(FacesContext facesContext, UIViewRoot view)
 391  
   {
 392  0
       return Boolean.TRUE.equals(facesContext.getAttributes().get(view));
 393  
   }
 394  
   
 395  
   /**
 396  
    * Saves a flag in the attribute map of the FacesContext to indicate
 397  
    * that the given UIViewRoot was already built with VDL.buildView().
 398  
    * 
 399  
    * @param facesContext
 400  
    * @param view
 401  
    */
 402  
   protected void setViewBuilt(FacesContext facesContext, UIViewRoot view)
 403  
   {
 404  0
       facesContext.getAttributes().put(view, Boolean.TRUE);
 405  0
   }
 406  
 
 407  
   /**
 408  
    * Trys to obtain a ResponseSwitch from the Response.
 409  
    * @param response
 410  
    * @return if found, the ResponseSwitch, null otherwise
 411  
    */
 412  
   private static ResponseSwitch getResponseSwitch(Object response)
 413  
   {
 414  
       // unwrap the response until we find a ResponseSwitch
 415  0
       while (response != null)
 416  
       {
 417  0
           if (response instanceof ResponseSwitch)
 418  
           {
 419  
               // found
 420  0
               return (ResponseSwitch) response;
 421  
           }
 422  0
           if (response instanceof ServletResponseWrapper)
 423  
           {
 424  
               // unwrap
 425  0
               response = ((ServletResponseWrapper) response).getResponse();
 426  
           }
 427  
           // no more possibilities to find a ResponseSwitch
 428  
           break; 
 429  
       }
 430  0
       return null; // not found
 431  
   }
 432  
   
 433  
   /**
 434  
    * Try to create a ResponseSwitch for this response.
 435  
    * @param response
 436  
    * @return the created ResponseSwitch, if there is a ResponseSwitch 
 437  
    *         implementation for the given response, null otherwise
 438  
    */
 439  
   private static ResponseSwitch createResponseSwitch(Object response)
 440  
   {
 441  0
       if (response instanceof HttpServletResponse)
 442  
       {
 443  0
           return new HttpServletResponseSwitch((HttpServletResponse) response);
 444  
       }
 445  0
       else if (response instanceof ServletResponse)
 446  
       {
 447  0
           return new ServletResponseSwitch((ServletResponse) response);
 448  
       }
 449  0
       return null;
 450  
   }
 451  
 
 452  
   /**
 453  
    * Writes the response and replaces the state marker tags with the state information for the current context
 454  
    */
 455  
 /*  private static class StateMarkerAwareWriter extends Writer
 456  
   {
 457  
     private StringBuilder buf;
 458  
 
 459  
     public StateMarkerAwareWriter()
 460  
     {
 461  
         this.buf = new StringBuilder();
 462  
     }
 463  
 
 464  
     @Override
 465  
     public void close() throws IOException
 466  
     {
 467  
     }
 468  
 
 469  
     @Override
 470  
     public void flush() throws IOException
 471  
     {
 472  
     }
 473  
 
 474  
     @Override
 475  
     public void write(char[] cbuf, int off, int len) throws IOException
 476  
     {
 477  
       if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0))
 478  
       {
 479  
         throw new IndexOutOfBoundsException();
 480  
       }
 481  
       else if (len == 0)
 482  
       {
 483  
         return;
 484  
       }
 485  
       buf.append(cbuf, off, len);
 486  
     }
 487  
 
 488  
     public StringBuilder getStringBuilder()
 489  
     {
 490  
       return buf;
 491  
     }
 492  
   }*/
 493  
 }