Coverage Report - org.apache.myfaces.application.jsp.JspStateManagerImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
JspStateManagerImpl
0%
0/301
0%
0/190
0
JspStateManagerImpl$1
0%
0/2
N/A
0
JspStateManagerImpl$SerializedViewCollection
0%
0/58
0%
0/38
0
JspStateManagerImpl$SerializedViewKey
0%
0/31
0%
0/22
0
 
 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.jsp;
 20  
 
 21  
 import org.apache.commons.collections.map.AbstractReferenceMap;
 22  
 import org.apache.commons.collections.map.ReferenceMap;
 23  
 import org.apache.commons.logging.Log;
 24  
 import org.apache.commons.logging.LogFactory;
 25  
 import org.apache.myfaces.application.MyfacesStateManager;
 26  
 import org.apache.myfaces.application.TreeStructureManager;
 27  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
 28  
 import org.apache.myfaces.renderkit.MyfacesResponseStateManager;
 29  
 import org.apache.myfaces.shared_impl.renderkit.RendererUtils;
 30  
 import org.apache.myfaces.shared_impl.util.MyFacesObjectInputStream;
 31  
 
 32  
 import javax.faces.FacesException;
 33  
 import javax.faces.FactoryFinder;
 34  
 import javax.faces.component.NamingContainer;
 35  
 import javax.faces.component.UIComponent;
 36  
 import javax.faces.component.UIViewRoot;
 37  
 import javax.faces.context.ExternalContext;
 38  
 import javax.faces.context.FacesContext;
 39  
 import javax.faces.render.RenderKit;
 40  
 import javax.faces.render.RenderKitFactory;
 41  
 import javax.faces.render.ResponseStateManager;
 42  
 import java.io.*;
 43  
 import java.lang.reflect.Method;
 44  
 import java.security.AccessController;
 45  
 import java.security.PrivilegedActionException;
 46  
 import java.security.PrivilegedExceptionAction;
 47  
 import java.util.*;
 48  
 import java.util.zip.GZIPInputStream;
 49  
 import java.util.zip.GZIPOutputStream;
 50  
 
 51  
 /**
 52  
  * Default StateManager implementation for use when views are defined
 53  
  * via tags in JSP pages.
 54  
  *
 55  
  * @author Thomas Spiegl (latest modification by $Author: lu4242 $)
 56  
  * @author Manfred Geiler
 57  
  * @version $Revision: 951800 $ $Date: 2010-06-05 21:07:42 -0500 (Sat, 05 Jun 2010) $
 58  
  */
 59  0
 public class JspStateManagerImpl
 60  
     extends MyfacesStateManager
 61  
 {
 62  0
     private static final Log log = LogFactory.getLog(JspStateManagerImpl.class);
 63  0
     private static final String SERIALIZED_VIEW_SESSION_ATTR
 64  
             = JspStateManagerImpl.class.getName() + ".SERIALIZED_VIEW";
 65  0
     private static final String SERIALIZED_VIEW_REQUEST_ATTR
 66  
             = JspStateManagerImpl.class.getName() + ".SERIALIZED_VIEW";
 67  0
     private static final String RESTORED_SERIALIZED_VIEW_REQUEST_ATTR
 68  
     = JspStateManagerImpl.class.getName() + ".RESTORED_SERIALIZED_VIEW";
 69  
 
 70  
     /**
 71  
      * Only applicable if state saving method is "server" (= default).
 72  
      * Defines the amount (default = 20) of the latest views are stored in session.
 73  
      */
 74  
     @JSFWebConfigParam(defaultValue="20",since="1.1")
 75  
     private static final String NUMBER_OF_VIEWS_IN_SESSION_PARAM = "org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION";
 76  
 
 77  
     /**
 78  
      * Default value for <code>org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION</code> context parameter.
 79  
      */
 80  
     private static final int DEFAULT_NUMBER_OF_VIEWS_IN_SESSION = 20;
 81  
 
 82  
     /**
 83  
      * Only applicable if state saving method is "server" (= default).
 84  
      * If <code>true</code> (default) the state will be serialized to a byte stream before it is written to the session.
 85  
      * If <code>false</code> the state will not be serialized to a byte stream.
 86  
      */
 87  
     @JSFWebConfigParam(defaultValue="true",since="1.1")
 88  
     private static final String SERIALIZE_STATE_IN_SESSION_PARAM = "org.apache.myfaces.SERIALIZE_STATE_IN_SESSION";
 89  
 
 90  
     /**
 91  
      * Only applicable if state saving method is "server" (= default) and if <code>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</code> is <code>true</code> (= default).
 92  
      * If <code>true</code> (default) the serialized state will be compressed before it is written to the session.
 93  
      * If <code>false</code> the state will not be compressed.
 94  
      */
 95  
     @JSFWebConfigParam(defaultValue="true",since="1.1")
 96  
     private static final String COMPRESS_SERVER_STATE_PARAM = "org.apache.myfaces.COMPRESS_STATE_IN_SESSION";
 97  
 
 98  
     /**
 99  
      * Default value for <code>org.apache.myfaces.COMPRESS_STATE_IN_SESSION</code> context parameter.
 100  
      */
 101  
     private static final boolean DEFAULT_COMPRESS_SERVER_STATE_PARAM = true;
 102  
 
 103  
     /**
 104  
      * Default value for <code>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</code> context parameter.
 105  
      */
 106  
     private static final boolean DEFAULT_SERIALIZE_STATE_IN_SESSION = true;
 107  
 
 108  
     /**
 109  
      * Define the way of handle old view references(views removed from session), making possible to
 110  
      * store it in a cache, so the state manager first try to get the view from the session. If is it
 111  
      * not found and soft or weak ReferenceMap is used, it try to get from it.
 112  
      * <p>
 113  
      * Only applicable if state saving method is "server" (= default).
 114  
      * </p>
 115  
      * <p>
 116  
      * The gc is responsible for remove the views, according to the rules used for soft, weak or phantom
 117  
      * references. If a key in soft and weak mode is garbage collected, its values are purged.
 118  
      * </p>
 119  
      * <p>
 120  
      * By default no cache is used, so views removed from session became phantom references.
 121  
      * </p>
 122  
      * <ul> 
 123  
      * <li> off, no: default, no cache is used</li> 
 124  
      * <li> hard-soft: use an ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.SOFT)</li>
 125  
      * <li> soft: use an ReferenceMap(AbstractReferenceMap.SOFT, AbstractReferenceMap.SOFT, true) </li>
 126  
      * <li> soft-weak: use an ReferenceMap(AbstractReferenceMap.SOFT, AbstractReferenceMap.WEAK, true) </li>
 127  
      * <li> weak: use an ReferenceMap(AbstractReferenceMap.WEAK, AbstractReferenceMap.WEAK, true) </li>
 128  
      * </ul>
 129  
      * 
 130  
      */
 131  
     @JSFWebConfigParam(defaultValue="off", expectedValues="off, no, hard-soft, soft, soft-weak, weak", since="1.2.5")
 132  
     private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE = "org.apache.myfaces.CACHE_OLD_VIEWS_IN_SESSION_MODE";
 133  
     
 134  
     /**
 135  
      * This option uses an hard-soft ReferenceMap, but it could cause a 
 136  
      * memory leak, because the keys are not removed by any method
 137  
      * (MYFACES-1660). So use with caution.
 138  
      */
 139  
     private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE_HARD_SOFT = "hard-soft";
 140  
     
 141  
     private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT = "soft";
 142  
     
 143  
     private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT_WEAK = "soft-weak";
 144  
     
 145  
     private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK = "weak";
 146  
     
 147  
     private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF = "off";
 148  
 
 149  
     private static final int UNCOMPRESSED_FLAG = 0;
 150  
     private static final int COMPRESSED_FLAG = 1;
 151  
 
 152  
     private static final int JSF_SEQUENCE_INDEX = 0;
 153  
 
 154  0
     private RenderKitFactory _renderKitFactory = null;
 155  
 
 156  
     public JspStateManagerImpl()
 157  0
     {
 158  0
         if (log.isTraceEnabled()) log.trace("New JspStateManagerImpl instance created");
 159  0
     }
 160  
 
 161  
     protected Object getComponentStateToSave(FacesContext facesContext)
 162  
     {
 163  0
         if (log.isTraceEnabled()) log.trace("Entering getComponentStateToSave");
 164  
 
 165  0
         UIViewRoot viewRoot = facesContext.getViewRoot();
 166  0
         if (viewRoot.isTransient())
 167  
         {
 168  0
             return null;
 169  
         }
 170  
 
 171  0
         Object serializedComponentStates = viewRoot.processSaveState(facesContext);
 172  
         //Locale is a state attribute of UIViewRoot and need not be saved explicitly
 173  0
         if (log.isTraceEnabled()) log.trace("Exiting getComponentStateToSave");
 174  0
         return serializedComponentStates;
 175  
     }
 176  
 
 177  
     /**
 178  
      * Return an object which contains info about the UIComponent type
 179  
      * of each node in the view tree. This allows an identical UIComponent
 180  
      * tree to be recreated later, though all the components will have
 181  
      * just default values for their members.
 182  
      */
 183  
     protected Object getTreeStructureToSave(FacesContext facesContext)
 184  
     {
 185  0
         if (log.isTraceEnabled()) log.trace("Entering getTreeStructureToSave");
 186  0
         UIViewRoot viewRoot = facesContext.getViewRoot();
 187  0
         if (viewRoot.isTransient())
 188  
         {
 189  0
             return null;
 190  
         }
 191  0
         TreeStructureManager tsm = new TreeStructureManager();
 192  0
         Object retVal = tsm.buildTreeStructureToSave(viewRoot);
 193  0
         if (log.isTraceEnabled()) log.trace("Exiting getTreeStructureToSave");
 194  0
         return retVal;
 195  
     }
 196  
 
 197  
     /**
 198  
      * Given a tree of UIComponent objects created the default constructor
 199  
      * for each node, retrieve saved state info (from either the client or
 200  
      * the server) and walk the tree restoring the members of each node
 201  
      * from the saved state information.
 202  
      */
 203  
     protected void restoreComponentState(FacesContext facesContext,
 204  
                                          UIViewRoot uiViewRoot,
 205  
                                          String renderKitId)
 206  
     {
 207  0
         if (log.isTraceEnabled()) log.trace("Entering restoreComponentState");
 208  
 
 209  
         //===========================================
 210  
         // first, locate the saved state information
 211  
         //===========================================
 212  
 
 213  0
         RenderKit renderKit = getRenderKitFactory().getRenderKit(facesContext, renderKitId);
 214  0
         ResponseStateManager responseStateManager = renderKit.getResponseStateManager();
 215  
 
 216  
         Object serializedComponentStates;
 217  0
         if (isSavingStateInClient(facesContext))
 218  
         {
 219  0
             if (isLegacyResponseStateManager(responseStateManager))
 220  
             {
 221  0
                 serializedComponentStates = responseStateManager.getComponentStateToRestore(facesContext);
 222  
             }
 223  
             else
 224  
             {
 225  0
                 serializedComponentStates = responseStateManager.getState(facesContext, uiViewRoot.getViewId());
 226  
             }
 227  0
             if (serializedComponentStates == null)
 228  
             {
 229  0
                 log.error("No serialized component state found in client request!");
 230  
                 // mark UIViewRoot invalid by resetting view id
 231  0
                 uiViewRoot.setViewId(null);
 232  0
                 return;
 233  
             }
 234  
         }
 235  
         else
 236  
         {
 237  0
             Integer serverStateId = getServerStateId((Object[]) responseStateManager.getState(facesContext, uiViewRoot.getViewId()));
 238  
 
 239  0
             Object[] stateObj = (Object[])( (serverStateId == null)? null : getSerializedViewFromServletSession(facesContext, uiViewRoot.getViewId(), serverStateId) );
 240  0
             if (stateObj == null)
 241  
             {
 242  0
                  log.error("No serialized view found in server session!");
 243  
                 // mark UIViewRoot invalid by resetting view id
 244  0
                 uiViewRoot.setViewId(null);
 245  0
                 return;
 246  
             }
 247  0
             SerializedView serializedView = new SerializedView(stateObj[0], stateObj[1]);
 248  0
             serializedComponentStates = serializedView.getState();
 249  0
             if (serializedComponentStates == null)
 250  
             {
 251  0
                 log.error("No serialized component state found in server session!");
 252  0
                 return;
 253  
             }
 254  
         }
 255  
 
 256  0
         if (uiViewRoot.getRenderKitId() == null)
 257  
         {
 258  
             //Just to be sure...
 259  0
             uiViewRoot.setRenderKitId(renderKitId);
 260  
         }
 261  
 
 262  
         // now ask the view root component to restore its state
 263  0
         uiViewRoot.processRestoreState(facesContext, serializedComponentStates);
 264  
 
 265  0
         if (log.isTraceEnabled()) log.trace("Exiting restoreComponentState");
 266  0
     }
 267  
 
 268  
       protected Integer getServerStateId(Object[] state)
 269  
       {
 270  0
         if (state != null)
 271  
         {
 272  0
             Object serverStateId = state[JSF_SEQUENCE_INDEX];
 273  0
             if (serverStateId != null)
 274  
             {
 275  0
                 return Integer.valueOf((String) serverStateId, Character.MAX_RADIX);
 276  
             }
 277  
         }
 278  0
         return null;
 279  
     }
 280  
 
 281  
     /**
 282  
      * See getTreeStructureToSave.
 283  
      */
 284  
     protected UIViewRoot restoreTreeStructure(FacesContext facesContext,
 285  
                                               String viewId,
 286  
                                               String renderKitId)
 287  
     {
 288  0
         if (log.isTraceEnabled()) log.trace("Entering restoreTreeStructure");
 289  
 
 290  0
         RenderKit rk = getRenderKitFactory().getRenderKit(facesContext, renderKitId);
 291  0
         ResponseStateManager responseStateManager = rk.getResponseStateManager();
 292  
 
 293  
         UIViewRoot uiViewRoot;
 294  0
         if (isSavingStateInClient(facesContext))
 295  
         {
 296  
             //reconstruct tree structure from request
 297  0
             Object treeStructure = responseStateManager.getTreeStructureToRestore(facesContext, viewId);
 298  0
             if (treeStructure == null)
 299  
             {
 300  0
                 if (log.isDebugEnabled()) log.debug("Exiting restoreTreeStructure - No tree structure state found in client request");
 301  0
                 return null;
 302  
             }
 303  
 
 304  0
             TreeStructureManager tsm = new TreeStructureManager();
 305  0
             uiViewRoot = tsm.restoreTreeStructure(treeStructure);
 306  0
             if (log.isTraceEnabled()) log.trace("Tree structure restored from client request");
 307  0
         }
 308  
         else
 309  
         {
 310  
             //reconstruct tree structure from ServletSession
 311  0
             Integer serverStateId = getServerStateId((Object[]) responseStateManager.getState(facesContext, viewId));
 312  
 
 313  0
             Object[] stateObj = (Object[])( (serverStateId == null)? null : getSerializedViewFromServletSession(facesContext, viewId, serverStateId) );
 314  0
             if (stateObj == null)
 315  
             {
 316  0
                 if (log.isDebugEnabled()) log.debug("Exiting restoreTreeStructure - No serialized view found in server session!");
 317  0
                 return null;
 318  
             }
 319  
 
 320  0
             SerializedView serializedView = new SerializedView(stateObj[0], stateObj[1]);
 321  0
             Object treeStructure = serializedView.getStructure();
 322  0
             if (treeStructure == null)
 323  
             {
 324  0
                 if (log.isDebugEnabled()) log.debug("Exiting restoreTreeStructure - No tree structure state found in server session, former UIViewRoot must have been transient");
 325  0
                 return null;
 326  
             }
 327  
 
 328  0
             TreeStructureManager tsm = new TreeStructureManager();
 329  0
             uiViewRoot = tsm.restoreTreeStructure(serializedView.getStructure());
 330  0
             if (log.isTraceEnabled()) log.trace("Tree structure restored from server session");
 331  
         }
 332  
 
 333  0
         if (log.isTraceEnabled()) log.trace("Exiting restoreTreeStructure");
 334  0
         return uiViewRoot;
 335  
     }
 336  
 
 337  
     public UIViewRoot restoreView(FacesContext facesContext, String viewId, String renderKitId)
 338  
     {
 339  0
         if (log.isTraceEnabled()) log.trace("Entering restoreView - viewId: "+viewId+" ; renderKitId: "+renderKitId);
 340  
 
 341  0
         RenderKit renderKit = getRenderKitFactory().getRenderKit(facesContext, renderKitId);
 342  0
         ResponseStateManager responseStateManager = renderKit.getResponseStateManager();
 343  
 
 344  
         Object state;
 345  0
         if (isSavingStateInClient(facesContext))
 346  
         {
 347  0
             if (log.isTraceEnabled()) log.trace("Restoring view from client");
 348  
 
 349  0
             state = responseStateManager.getState(facesContext, viewId);
 350  
         }
 351  
         else
 352  
         {
 353  0
             if (log.isTraceEnabled()) log.trace("Restoring view from session");
 354  
 
 355  0
             Integer serverStateId = getServerStateId((Object[]) responseStateManager.getState(facesContext, viewId));
 356  
 
 357  0
             state = (serverStateId == null) ? null : getSerializedViewFromServletSession(facesContext, viewId, serverStateId);
 358  
         }
 359  
 
 360  0
         UIViewRoot uiViewRoot = null;
 361  
 
 362  0
         if (state != null) {
 363  0
             Object[] stateArray = (Object[])state;
 364  0
             TreeStructureManager tsm = new TreeStructureManager();
 365  0
             uiViewRoot = tsm.restoreTreeStructure(stateArray[0]);
 366  
 
 367  0
             if (uiViewRoot != null) {
 368  0
                 uiViewRoot.processRestoreState(facesContext, stateArray[1]);
 369  
             }
 370  
         }
 371  
 
 372  0
         if (log.isTraceEnabled()) log.trace("Exiting restoreView - "+viewId);
 373  
 
 374  0
         return uiViewRoot;
 375  
     }
 376  
 
 377  
     public SerializedView saveSerializedView(FacesContext facesContext) throws IllegalStateException
 378  
     {
 379  0
         if (log.isTraceEnabled()) log.trace("Entering saveSerializedView");
 380  
 
 381  0
         checkForDuplicateIds(facesContext, facesContext.getViewRoot(), new HashSet<String>());
 382  
 
 383  0
         if (log.isTraceEnabled()) log.trace("Processing saveSerializedView - Checked for duplicate Ids");
 384  
 
 385  0
         ExternalContext externalContext = facesContext.getExternalContext();
 386  
 
 387  
         // SerializedView already created before within this request?
 388  0
         Object serializedView = externalContext.getRequestMap()
 389  
                                                             .get(SERIALIZED_VIEW_REQUEST_ATTR);
 390  0
         if (serializedView == null)
 391  
         {
 392  0
             if (log.isTraceEnabled()) log.trace("Processing saveSerializedView - create new serialized view");
 393  
 
 394  
             // first call to saveSerializedView --> create SerializedView
 395  0
             Object treeStruct = getTreeStructureToSave(facesContext);
 396  0
             Object compStates = getComponentStateToSave(facesContext);
 397  0
             serializedView = new Object[] {treeStruct, compStates};
 398  0
             externalContext.getRequestMap().put(SERIALIZED_VIEW_REQUEST_ATTR,
 399  
                                                 serializedView);
 400  
 
 401  0
             if (log.isTraceEnabled()) log.trace("Processing saveSerializedView - new serialized view created");
 402  
         }
 403  
 
 404  0
         Object[] serializedViewArray = (Object[]) serializedView;
 405  
 
 406  0
         if (!isSavingStateInClient(facesContext))
 407  
         {
 408  0
             if (log.isTraceEnabled()) log.trace("Processing saveSerializedView - server-side state saving - save state");
 409  
             //save state in server session
 410  0
             saveSerializedViewInServletSession(facesContext, serializedView);
 411  
 
 412  0
             if (log.isTraceEnabled()) log.trace("Exiting saveSerializedView - server-side state saving - saved state");
 413  0
             return new SerializedView(serializedViewArray[0], new Object[0]);
 414  
         }
 415  
 
 416  0
         if (log.isTraceEnabled()) log.trace("Exiting saveSerializedView - client-side state saving");
 417  
 
 418  0
         return new SerializedView(serializedViewArray[0], serializedViewArray[1]);
 419  
     }
 420  
 
 421  
     private static void checkForDuplicateIds(FacesContext context,
 422  
                                              UIComponent component,
 423  
                                              Set<String> ids)
 424  
     {
 425  0
         String id = component.getId();
 426  0
         if (id != null && !ids.add(id))
 427  
         {
 428  0
             throw new IllegalStateException("Client-id : "+id +
 429  
                                             " is duplicated in the faces tree. Component : "+component.getClientId(context)+", path: "+
 430  
                                             getPathToComponent(component));
 431  
         }
 432  0
         if (component instanceof NamingContainer)
 433  
         {
 434  0
             ids = new HashSet<String>();
 435  
         }
 436  0
         Iterator it = component.getFacetsAndChildren();
 437  0
         while (it.hasNext())
 438  
         {
 439  0
             UIComponent kid = (UIComponent) it.next();
 440  0
             checkForDuplicateIds(context, kid, ids);
 441  0
         }
 442  0
     }
 443  
 
 444  
     private static String getPathToComponent(UIComponent component)
 445  
     {
 446  0
         StringBuffer buf = new StringBuffer();
 447  
 
 448  0
         if(component == null)
 449  
         {
 450  0
             buf.append("{Component-Path : ");
 451  0
             buf.append("[null]}");
 452  0
             return buf.toString();
 453  
         }
 454  
 
 455  0
         getPathToComponent(component,buf);
 456  
 
 457  0
         buf.insert(0,"{Component-Path : ");
 458  0
         buf.append("}");
 459  
 
 460  0
         return buf.toString();
 461  
     }
 462  
 
 463  
     private static void getPathToComponent(UIComponent component, StringBuffer buf)
 464  
     {
 465  0
         if(component == null)
 466  0
             return;
 467  
 
 468  0
         StringBuffer intBuf = new StringBuffer();
 469  
 
 470  0
         intBuf.append("[Class: ");
 471  0
         intBuf.append(component.getClass().getName());
 472  0
         if(component instanceof UIViewRoot)
 473  
         {
 474  0
             intBuf.append(",ViewId: ");
 475  0
             intBuf.append(((UIViewRoot) component).getViewId());
 476  
         }
 477  
         else
 478  
         {
 479  0
             intBuf.append(",Id: ");
 480  0
             intBuf.append(component.getId());
 481  
         }
 482  0
         intBuf.append("]");
 483  
 
 484  0
         buf.insert(0,intBuf.toString());
 485  
 
 486  0
         if(component!=null)
 487  
         {
 488  0
             getPathToComponent(component.getParent(),buf);
 489  
         }
 490  0
     }
 491  
 
 492  
     public void writeState(FacesContext facesContext,
 493  
                            SerializedView serializedView) throws IOException
 494  
     {
 495  0
         if (log.isTraceEnabled()) log.trace("Entering writeState");
 496  
 
 497  0
         UIViewRoot uiViewRoot = facesContext.getViewRoot();
 498  
         //save state in response (client)
 499  0
         RenderKit renderKit = getRenderKitFactory().getRenderKit(facesContext, uiViewRoot.getRenderKitId());
 500  0
         ResponseStateManager responseStateManager = renderKit.getResponseStateManager();
 501  
 
 502  0
         if (isLegacyResponseStateManager(responseStateManager))
 503  
         {
 504  0
             responseStateManager.writeState(facesContext, serializedView);
 505  
         }
 506  0
         else if (!isSavingStateInClient(facesContext))
 507  
         {
 508  0
             Object[] state = new Object[2];
 509  0
             state[JSF_SEQUENCE_INDEX] = Integer.toString(getNextViewSequence(facesContext), Character.MAX_RADIX);
 510  0
             responseStateManager.writeState(facesContext, state);
 511  0
         }
 512  
         else
 513  
         {
 514  0
             Object[] state = new Object[2];
 515  0
             state[0] = serializedView.getStructure();
 516  0
             state[1] = serializedView.getState();
 517  0
             responseStateManager.writeState(facesContext, state);
 518  
         }
 519  
 
 520  0
         if (log.isTraceEnabled()) log.trace("Exiting writeState");
 521  
 
 522  0
     }
 523  
 
 524  
     /**
 525  
      * MyFaces extension
 526  
      * @param facesContext
 527  
      * @param serializedView
 528  
      * @throws IOException
 529  
      */
 530  
     public void writeStateAsUrlParams(FacesContext facesContext,
 531  
                                       SerializedView serializedView) throws IOException
 532  
     {
 533  0
         if (log.isTraceEnabled()) log.trace("Entering writeStateAsUrlParams");
 534  
 
 535  0
         if (isSavingStateInClient(facesContext))
 536  
         {
 537  0
             if (log.isTraceEnabled()) log.trace("Processing writeStateAsUrlParams - client-side state saving writing state");
 538  
 
 539  0
             UIViewRoot uiViewRoot = facesContext.getViewRoot();
 540  
             //save state in response (client)
 541  0
             RenderKit renderKit = getRenderKitFactory().getRenderKit(facesContext, uiViewRoot.getRenderKitId());
 542  0
             ResponseStateManager responseStateManager = renderKit.getResponseStateManager();
 543  0
             if (responseStateManager instanceof MyfacesResponseStateManager)
 544  
             {
 545  0
                 ((MyfacesResponseStateManager)responseStateManager).writeStateAsUrlParams(facesContext,
 546  
                                                                                           serializedView);
 547  
             }
 548  
             else
 549  
             {
 550  0
                 log.error("ResponseStateManager of render kit " + uiViewRoot.getRenderKitId() + " is no MyfacesResponseStateManager and does not support saving state in url parameters.");
 551  
             }
 552  
         }
 553  
 
 554  0
         if (log.isTraceEnabled()) log.trace("Exiting writeStateAsUrlParams");
 555  0
     }
 556  
 
 557  
     //helpers
 558  
 
 559  
     protected RenderKitFactory getRenderKitFactory()
 560  
     {
 561  0
         if (_renderKitFactory == null)
 562  
         {
 563  0
             _renderKitFactory = (RenderKitFactory)FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
 564  
         }
 565  0
         return _renderKitFactory;
 566  
     }
 567  
 
 568  
     protected void saveSerializedViewInServletSession(FacesContext context,
 569  
                                                       Object serializedView)
 570  
     {
 571  0
         Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
 572  0
         SerializedViewCollection viewCollection = (SerializedViewCollection) sessionMap
 573  
                 .get(SERIALIZED_VIEW_SESSION_ATTR);
 574  0
         if (viewCollection == null)
 575  
         {
 576  0
             viewCollection = new SerializedViewCollection();
 577  0
             sessionMap.put(SERIALIZED_VIEW_SESSION_ATTR, viewCollection);
 578  
         }
 579  0
         viewCollection.add(context, serializeView(context, serializedView));
 580  
         // replace the value to notify the container about the change
 581  0
         sessionMap.put(SERIALIZED_VIEW_SESSION_ATTR, viewCollection);
 582  0
     }
 583  
 
 584  
     protected Object getSerializedViewFromServletSession(FacesContext context, String viewId, Integer sequence)
 585  
     {
 586  0
         ExternalContext externalContext = context.getExternalContext();
 587  0
         Map<String, Object> requestMap = externalContext.getRequestMap();
 588  0
         Object serializedView = null;
 589  0
         if (requestMap.containsKey(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR))
 590  
         {
 591  0
             serializedView = requestMap.get(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR);
 592  
         }
 593  
         else
 594  
         {
 595  0
             SerializedViewCollection viewCollection = (SerializedViewCollection) externalContext
 596  
                     .getSessionMap().get(SERIALIZED_VIEW_SESSION_ATTR);
 597  0
             if (viewCollection != null)
 598  
             {
 599  
                 /*
 600  
                 String sequenceStr = externalContext.getRequestParameterMap().get(
 601  
                        RendererUtils.SEQUENCE_PARAM);
 602  
                 Integer sequence = null;
 603  
                 if (sequenceStr == null)
 604  
                 {
 605  
                     // use latest sequence
 606  
                     Map map = externalContext.getSessionMap();
 607  
                     sequence = (Integer) map.get(RendererUtils.SEQUENCE_PARAM);
 608  
                 }
 609  
                 else
 610  
                 {
 611  
                     sequence = new Integer(sequenceStr);
 612  
                 }
 613  
                 */
 614  0
                 if (sequence != null)
 615  
                 {
 616  0
                     Object state = viewCollection.get(sequence, viewId);
 617  0
                     if (state != null)
 618  
                     {
 619  0
                         serializedView = deserializeView(state);
 620  
                     }
 621  
                 }
 622  
             }
 623  0
             requestMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR, serializedView);
 624  0
             nextViewSequence(context);
 625  
         }
 626  0
         return serializedView;
 627  
     }
 628  
 
 629  
     protected int getNextViewSequence(FacesContext context)
 630  
     {
 631  0
         ExternalContext externalContext = context.getExternalContext();
 632  
 
 633  0
         if (!externalContext.getRequestMap().containsKey(RendererUtils.SEQUENCE_PARAM))
 634  
         {
 635  0
             nextViewSequence(context);
 636  
         }
 637  
 
 638  0
         Integer sequence = (Integer) externalContext.getRequestMap().get(RendererUtils.SEQUENCE_PARAM);
 639  0
         return sequence.intValue();
 640  
     }
 641  
 
 642  
     protected void nextViewSequence(FacesContext facescontext)
 643  
     {
 644  0
         ExternalContext externalContext = facescontext.getExternalContext();
 645  0
         Object sessionObj = externalContext.getSession(true);
 646  0
         synchronized(sessionObj) // synchronized to increase sequence if multiple requests
 647  
                                  // are handled at the same time for the session
 648  
         {
 649  0
             Map<String, Object> map = externalContext.getSessionMap();
 650  0
             Integer sequence = (Integer) map.get(RendererUtils.SEQUENCE_PARAM);
 651  0
             if(sequence == null || sequence.intValue() == Integer.MAX_VALUE)
 652  
             {
 653  0
                 sequence = Integer.valueOf(1);
 654  
             }
 655  
             else
 656  
             {
 657  0
                 sequence = Integer.valueOf(sequence.intValue() + 1);
 658  
             }
 659  0
             map.put(RendererUtils.SEQUENCE_PARAM, sequence);
 660  0
             externalContext.getRequestMap().put(RendererUtils.SEQUENCE_PARAM, sequence);
 661  0
         }
 662  0
     }
 663  
 
 664  
     protected Object serializeView(FacesContext context, Object serializedView)
 665  
     {
 666  0
         if (log.isTraceEnabled()) log.trace("Entering serializeView");
 667  
 
 668  0
         if(isSerializeStateInSession(context))
 669  
         {
 670  0
             if (log.isTraceEnabled()) log.trace("Processing serializeView - serialize state in session");
 671  
 
 672  0
             ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
 673  
             try
 674  
             {
 675  0
                 OutputStream os = baos;
 676  0
                 if(isCompressStateInSession(context))
 677  
                 {
 678  0
                     if (log.isTraceEnabled()) log.trace("Processing serializeView - serialize compressed");
 679  
 
 680  0
                     os.write(COMPRESSED_FLAG);
 681  0
                     os = new GZIPOutputStream(os, 1024);
 682  
                 }
 683  
                 else
 684  
                 {
 685  0
                     if (log.isTraceEnabled()) log.trace("Processing serializeView - serialize uncompressed");
 686  
 
 687  0
                     os.write(UNCOMPRESSED_FLAG);
 688  
                 }
 689  
 
 690  0
                 Object[] stateArray = (Object[]) serializedView;
 691  
 
 692  0
                 ObjectOutputStream out = new ObjectOutputStream(os);
 693  0
                 out.writeObject(stateArray[0]);
 694  0
                 out.writeObject(stateArray[1]);
 695  0
                 out.close();
 696  0
                 baos.close();
 697  
 
 698  0
                 if (log.isTraceEnabled()) log.trace("Exiting serializeView - serialized. Bytes : "+baos.size());
 699  0
                 return baos.toByteArray();
 700  
             }
 701  0
             catch (IOException e)
 702  
             {
 703  0
                 log.error("Exiting serializeView - Could not serialize state: " + e.getMessage(), e);
 704  0
                 return null;
 705  
             }
 706  
         }
 707  
 
 708  
 
 709  0
         if (log.isTraceEnabled())
 710  0
             log.trace("Exiting serializeView - do not serialize state in session.");
 711  
 
 712  0
         return serializedView;
 713  
 
 714  
     }
 715  
 
 716  
     /**
 717  
      * Reads the value of the <code>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</code> context parameter.
 718  
      * @see SERIALIZE_STATE_IN_SESSION_PARAM
 719  
      * @param context <code>FacesContext</code> for the request we are processing.
 720  
      * @return boolean true, if the server state should be serialized in the session
 721  
      */
 722  
     protected boolean isSerializeStateInSession(FacesContext context)
 723  
     {
 724  0
         String value = context.getExternalContext().getInitParameter(
 725  
                 SERIALIZE_STATE_IN_SESSION_PARAM);
 726  0
         boolean serialize = DEFAULT_SERIALIZE_STATE_IN_SESSION;
 727  0
         if (value != null)
 728  
         {
 729  0
            serialize = Boolean.valueOf(value);
 730  
         }
 731  0
         return serialize;
 732  
     }
 733  
 
 734  
     /**
 735  
      * Reads the value of the <code>org.apache.myfaces.COMPRESS_STATE_IN_SESSION</code> context parameter.
 736  
      * @see COMPRESS_SERVER_STATE_PARAM
 737  
      * @param context <code>FacesContext</code> for the request we are processing.
 738  
      * @return boolean true, if the server state steam should be compressed
 739  
      */
 740  
     protected boolean isCompressStateInSession(FacesContext context)
 741  
     {
 742  0
         String value = context.getExternalContext().getInitParameter(
 743  
                 COMPRESS_SERVER_STATE_PARAM);
 744  0
         boolean compress = DEFAULT_COMPRESS_SERVER_STATE_PARAM;
 745  0
         if (value != null)
 746  
         {
 747  0
            compress = Boolean.valueOf(value);
 748  
         }
 749  0
         return compress;
 750  
     }
 751  
 
 752  
     protected Object deserializeView(Object state)
 753  
     {
 754  0
         if (log.isTraceEnabled()) log.trace("Entering deserializeView");
 755  
 
 756  0
         if(state instanceof byte[])
 757  
         {
 758  0
             if (log.isTraceEnabled()) log.trace("Processing deserializeView - deserializing serialized state. Bytes : "+((byte[]) state).length);
 759  
 
 760  
             try
 761  
             {
 762  0
                 ByteArrayInputStream bais = new ByteArrayInputStream((byte[]) state);
 763  0
                 InputStream is = bais;
 764  0
                 if(is.read() == COMPRESSED_FLAG)
 765  
                 {
 766  0
                     is = new GZIPInputStream(is);
 767  
                 }
 768  0
                 ObjectInputStream ois = null;
 769  
                 try
 770  
                 {
 771  0
                     final ObjectInputStream in = new MyFacesObjectInputStream(is);
 772  0
                     ois = in;
 773  0
                     Object object = null;
 774  0
                     if (System.getSecurityManager() != null) 
 775  
                     {
 776  0
                         object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object []>() 
 777  0
                         {
 778  
                             public Object[] run() throws PrivilegedActionException, IOException, ClassNotFoundException
 779  
                             {
 780  0
                                 return new Object[] {in.readObject(), in.readObject()};                                    
 781  
                             }
 782  
                         });
 783  
                     }
 784  
                     else
 785  
                     {
 786  0
                         object = new Object[] {in.readObject(), in.readObject()};
 787  
                     }
 788  0
                     return object;
 789  
                 }
 790  
                 finally
 791  
                 {
 792  0
                     if (ois != null)
 793  
                     {
 794  0
                         ois.close();
 795  0
                         ois = null;
 796  
                     }
 797  
                 }
 798  
             }
 799  0
             catch (PrivilegedActionException e) 
 800  
             {
 801  0
                 log.error("Exiting deserializeView - Could not deserialize state: " + e.getMessage(), e);
 802  0
                 return null;
 803  
             }
 804  0
             catch (IOException e)
 805  
             {
 806  0
                 log.error("Exiting deserializeView - Could not deserialize state: " + e.getMessage(), e);
 807  0
                 return null;
 808  
             }
 809  0
             catch (ClassNotFoundException e)
 810  
             {
 811  0
                 log.error("Exiting deserializeView - Could not deserialize state: " + e.getMessage(), e);
 812  0
                 return null;
 813  
             }
 814  
         }
 815  0
         else if (state instanceof Object[])
 816  
         {
 817  0
             if (log.isTraceEnabled()) log.trace("Exiting deserializeView - state not serialized.");
 818  
 
 819  0
             return state;
 820  
         }
 821  0
         else if(state == null)
 822  
         {
 823  0
             log.error("Exiting deserializeView - this method should not be called with a null-state.");
 824  0
             return null;
 825  
         }
 826  
         else
 827  
         {
 828  0
             log.error("Exiting deserializeView - this method should not be called with a state of type : "+state.getClass());
 829  0
             return null;
 830  
         }
 831  
     }
 832  
 
 833  
     private boolean isLegacyResponseStateManager(ResponseStateManager instance) {
 834  
 
 835  0
         Method[] methods = instance.getClass().getMethods();
 836  0
         for (Method m : methods)
 837  
         {
 838  0
             if (m.getName().equals("getState") &&
 839  
                     Arrays.equals(m.getParameterTypes(),new Class[] {FacesContext.class, String.class}))
 840  
             {
 841  0
                  return false;
 842  
             }
 843  
         }
 844  
 
 845  0
         return true;
 846  
     }
 847  
 
 848  0
     protected static class SerializedViewCollection implements Serializable
 849  
     {
 850  
         private static final long serialVersionUID = -3734849062185115847L;
 851  
 
 852  0
         private final List<Object> _keys = new ArrayList<Object>(DEFAULT_NUMBER_OF_VIEWS_IN_SESSION);
 853  0
         private final Map<Object, Object> _serializedViews = new HashMap<Object, Object>();
 854  
 
 855  
         // old views will be hold as soft references which will be removed by
 856  
         // the garbage collector if free memory is low
 857  0
         private transient Map<Object, Object> _oldSerializedViews = null;
 858  
 
 859  
         public synchronized void add(FacesContext context, Object state)
 860  
         {
 861  0
             Object key = new SerializedViewKey(context);
 862  0
             _serializedViews.put(key, state);
 863  
 
 864  0
             while (_keys.remove(key));
 865  0
             _keys.add(key);
 866  
 
 867  0
             int views = getNumberOfViewsInSession(context);
 868  0
             while (_keys.size() > views)
 869  
             {
 870  0
                 key = _keys.remove(0);
 871  0
                 Object oldView = _serializedViews.remove(key);
 872  0
                 if (oldView != null && 
 873  
                     !CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF.equals(getCacheOldViewsInSessionMode(context))) 
 874  
                 {
 875  0
                     getOldSerializedViewsMap().put(key, oldView);
 876  
                 }
 877  0
             }
 878  0
         }
 879  
 
 880  
         /**
 881  
          * Reads the amount (default = 20) of views to be stored in session.
 882  
          * @see NUMBER_OF_VIEWS_IN_SESSION_PARAM
 883  
          * @param context FacesContext for the current request, we are processing
 884  
          * @return Number vf views stored in the session
 885  
          */
 886  
         protected int getNumberOfViewsInSession(FacesContext context)
 887  
         {
 888  0
             String value = context.getExternalContext().getInitParameter(
 889  
                     NUMBER_OF_VIEWS_IN_SESSION_PARAM);
 890  0
             int views = DEFAULT_NUMBER_OF_VIEWS_IN_SESSION;
 891  0
             if (value != null)
 892  
             {
 893  
                 try
 894  
                 {
 895  0
                     views = Integer.parseInt(value);
 896  0
                     if (views <= 0)
 897  
                     {
 898  0
                         log.error("Configured value for " + NUMBER_OF_VIEWS_IN_SESSION_PARAM
 899  
                                   + " is not valid, must be an value > 0, using default value ("
 900  
                                   + DEFAULT_NUMBER_OF_VIEWS_IN_SESSION);
 901  0
                         views = DEFAULT_NUMBER_OF_VIEWS_IN_SESSION;
 902  
                     }
 903  
                 }
 904  0
                 catch (Throwable e)
 905  
                 {
 906  0
                     log.error("Error determining the value for " + NUMBER_OF_VIEWS_IN_SESSION_PARAM
 907  
                               + ", expected an integer value > 0, using default value ("
 908  
                               + DEFAULT_NUMBER_OF_VIEWS_IN_SESSION + "): " + e.getMessage(), e);
 909  0
                 }
 910  
             }
 911  0
             return views;
 912  
         }
 913  
 
 914  
         /**
 915  
          * @return old serialized views map
 916  
          */
 917  
         protected Map<Object, Object> getOldSerializedViewsMap()
 918  
         {
 919  0
             FacesContext context = FacesContext.getCurrentInstance();
 920  0
             if (_oldSerializedViews == null && context != null)
 921  
             {
 922  0
                 String cacheMode = getCacheOldViewsInSessionMode(context); 
 923  0
                 if (CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK.equals(cacheMode))
 924  
                 {
 925  0
                     _oldSerializedViews = new ReferenceMap(AbstractReferenceMap.WEAK, AbstractReferenceMap.WEAK, true);
 926  
                 }
 927  0
                 else if (CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT_WEAK.equals(cacheMode))
 928  
                 {
 929  0
                     _oldSerializedViews = new ReferenceMap(AbstractReferenceMap.SOFT, AbstractReferenceMap.WEAK, true);
 930  
                 }
 931  0
                 else if (CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT.equals(cacheMode))
 932  
                 {
 933  0
                     _oldSerializedViews = new ReferenceMap(AbstractReferenceMap.SOFT, AbstractReferenceMap.SOFT, true);
 934  
                 }
 935  0
                 else if (CACHE_OLD_VIEWS_IN_SESSION_MODE_HARD_SOFT.equals(cacheMode))
 936  
                 {
 937  0
                     _oldSerializedViews = new ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.SOFT);
 938  
                 }
 939  
             }
 940  0
             return _oldSerializedViews;
 941  
         }
 942  
         
 943  
         /**
 944  
          * Reads the value of the <code>org.apache.myfaces.CACHE_OLD_VIEWS_IN_SESSION_MODE</code> context parameter.
 945  
          * 
 946  
          * @since 1.2.5
 947  
          * @param context
 948  
          * @return constant indicating caching mode
 949  
          * @see CACHE_OLD_VIEWS_IN_SESSION_MODE
 950  
          */
 951  
         protected String getCacheOldViewsInSessionMode(FacesContext context) {
 952  0
             String value = context.getExternalContext().getInitParameter(
 953  
                     CACHE_OLD_VIEWS_IN_SESSION_MODE);
 954  0
             if (value == null)
 955  
             {
 956  0
                 return CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF;
 957  
             }
 958  0
             else if (value.equalsIgnoreCase(CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT))
 959  
             {
 960  0
                 return CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT;
 961  
             }
 962  0
             else if (value.equalsIgnoreCase(CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT_WEAK))
 963  
             {
 964  0
                 return CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT_WEAK;
 965  
             }            
 966  0
             else if (value.equalsIgnoreCase(CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK))
 967  
             {
 968  0
                 return CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK;
 969  
             }
 970  0
             else if (value.equalsIgnoreCase(CACHE_OLD_VIEWS_IN_SESSION_MODE_HARD_SOFT))
 971  
             {
 972  0
                 return CACHE_OLD_VIEWS_IN_SESSION_MODE_HARD_SOFT;
 973  
             }
 974  
             else
 975  
             {
 976  0
                 return CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF;
 977  
             }
 978  
         }
 979  
         
 980  
         public Object get(Integer sequence, String viewId)
 981  
         {
 982  0
             Object key = new SerializedViewKey(viewId, sequence);
 983  0
             Object value = _serializedViews.get(key);
 984  0
             if (value == null)
 985  
             {
 986  0
                 Map<Object,Object> oldSerializedViewMap = getOldSerializedViewsMap();
 987  0
                 if (oldSerializedViewMap != null)
 988  
                 {
 989  0
                     value = oldSerializedViewMap.get(key);
 990  
                 }
 991  
             }
 992  0
             return value;
 993  
         }
 994  
     }
 995  
 
 996  
     protected static class SerializedViewKey implements Serializable
 997  
     {
 998  
         private static final long serialVersionUID = -1170697124386063642L;
 999  
 
 1000  
         private final String _viewId;
 1001  
         private final Integer _sequenceId;
 1002  
 
 1003  
         public SerializedViewKey(String viewId, Integer sequence)
 1004  0
         {
 1005  0
             _sequenceId = sequence;
 1006  0
             _viewId = viewId;
 1007  0
         }
 1008  
 
 1009  
         public SerializedViewKey(FacesContext context)
 1010  0
         {
 1011  0
             _sequenceId = RendererUtils.getViewSequence(context);
 1012  0
             _viewId = context.getViewRoot().getViewId();
 1013  0
         }
 1014  
 
 1015  
         @Override
 1016  
         public int hashCode()
 1017  
         {
 1018  0
             final int PRIME = 31;
 1019  0
             int result = 1;
 1020  0
             result = PRIME * result + ((_sequenceId == null) ? 0 : _sequenceId.hashCode());
 1021  0
             result = PRIME * result + ((_viewId == null) ? 0 : _viewId.hashCode());
 1022  0
             return result;
 1023  
         }
 1024  
 
 1025  
         @Override
 1026  
         public boolean equals(Object obj)
 1027  
         {
 1028  0
             if (this == obj)
 1029  0
                 return true;
 1030  0
             if (obj == null)
 1031  0
                 return false;
 1032  0
             if (getClass() != obj.getClass())
 1033  0
                 return false;
 1034  0
             final SerializedViewKey other = (SerializedViewKey) obj;
 1035  0
             if (_sequenceId == null)
 1036  
             {
 1037  0
                 if (other._sequenceId != null)
 1038  0
                     return false;
 1039  
             }
 1040  0
             else if (!_sequenceId.equals(other._sequenceId))
 1041  0
                 return false;
 1042  0
             if (_viewId == null)
 1043  
             {
 1044  0
                 if (other._viewId != null)
 1045  0
                     return false;
 1046  
             }
 1047  0
             else if (!_viewId.equals(other._viewId))
 1048  0
                 return false;
 1049  0
             return true;
 1050  
         }
 1051  
 
 1052  
     }
 1053  
 }