View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.view;
20  
21  import java.util.Collection;
22  import java.util.HashMap;
23  import java.util.Map;
24  import java.util.Set;
25  import javax.faces.component.StateHolder;
26  import javax.faces.context.FacesContext;
27  import javax.faces.event.PreDestroyViewMapEvent;
28  import org.apache.myfaces.spi.ViewScopeProvider;
29  import org.apache.myfaces.spi.ViewScopeProviderFactory;
30  
31  /**
32   * This wrapper has these objectives:
33   * 
34   * - Isolate the part that needs to be saved with the view (viewScopeId) from
35   *   the part that should remain into session (bean map). This class will be
36   *   serialized when UIViewRoot.saveState() is called.
37   * - Decouple the way how the view scope map is stored. For example, in 
38   *   CDI view scope a session scope bean is used, and in default view scope
39   *   the same session map is used but using a prefix.
40   *
41   * @author Leonardo Uribe
42   */
43  public class ViewScopeProxyMap implements Map<String, Object>, StateHolder
44  {
45      private String _viewScopeId;
46      
47      private transient Map<String, Object> _delegate;
48  
49      public ViewScopeProxyMap()
50      {
51      }
52      
53      
54      public String getViewScopeId()
55      {
56          return _viewScopeId;
57      }
58      
59      public void forceCreateWrappedMap(FacesContext facesContext)
60      {
61          getWrapped();
62      }
63      
64      public Map<String, Object> getWrapped()
65      {
66          if (_delegate == null)
67          {
68              FacesContext facesContext = FacesContext.getCurrentInstance();
69              
70              if (facesContext != null)
71              {
72                  ViewScopeProviderFactory factory = ViewScopeProviderFactory.getViewScopeHandlerFactory(
73                      facesContext.getExternalContext());
74  
75                  ViewScopeProvider handler = factory.getViewScopeHandler(facesContext.getExternalContext());
76  
77                  if (_viewScopeId == null)
78                  {
79                      _viewScopeId = handler.generateViewScopeId(facesContext);
80                      _delegate = handler.createViewScopeMap(facesContext, _viewScopeId);
81                  }
82                  else
83                  {
84                      _delegate = handler.restoreViewScopeMap(facesContext, _viewScopeId);
85                  }
86              }
87              else
88              {
89                  // In junit test cases, where there is no facesContext instance, it is enough to
90                  // just get a blank instance.
91                  _delegate = new ViewScope();
92              }
93          }
94          return _delegate;
95      }
96      
97      public int size()
98      {
99          return getWrapped().size();
100     }
101 
102     public boolean isEmpty()
103     {
104         return getWrapped().isEmpty();
105     }
106 
107     public boolean containsKey(Object key)
108     {
109         return getWrapped().containsKey(key);
110     }
111 
112     public boolean containsValue(Object value)
113     {
114         return getWrapped().containsValue(value);
115     }
116 
117     public Object get(Object key)
118     {
119         return getWrapped().get(key);
120     }
121 
122     public Object put(String key, Object value)
123     {
124         return getWrapped().put(key, value);
125     }
126 
127     public Object remove(Object key)
128     {
129         return getWrapped().remove(key);
130     }
131 
132     public void putAll(Map<? extends String, ? extends Object> m)
133     {
134         getWrapped().putAll(m);
135     }
136 
137     public void clear()
138     {
139         /*
140          * The returned Map must be implemented such that calling clear() on the Map causes
141          * Application.publishEvent(java.lang.Class, java.lang.Object) to be called, passing
142          * ViewMapDestroyedEvent.class as the first argument and this UIViewRoot instance as the second argument.
143          */
144         FacesContext facesContext = FacesContext.getCurrentInstance();
145         facesContext.getApplication().publishEvent(facesContext, 
146                 PreDestroyViewMapEvent.class, facesContext.getViewRoot());
147 
148         getWrapped().clear();
149     }
150 
151     public Set<String> keySet()
152     {
153         return getWrapped().keySet();
154     }
155 
156     public Collection<Object> values()
157     {
158         return getWrapped().values();
159     }
160 
161     public Set<Entry<String, Object>> entrySet()
162     {
163         return getWrapped().entrySet();
164     }
165 
166     public void restoreState(FacesContext context, Object state)
167     {
168         _viewScopeId = (String) state;
169     }
170 
171     public Object saveState(FacesContext context)
172     {
173         return _viewScopeId;
174     }
175 
176     public boolean isTransient()
177     {
178         return false;
179     }
180 
181     public void setTransient(boolean newTransientValue)
182     {
183     }
184     
185     private static class ViewScope extends HashMap<String, Object>
186     {
187         
188         private static final long serialVersionUID = -1088293802269478164L;
189         
190         @Override
191         public void clear()
192         {
193             /*
194              * The returned Map must be implemented such that calling clear() on the Map causes
195              * Application.publishEvent(java.lang.Class, java.lang.Object) to be called, passing
196              * ViewMapDestroyedEvent.class as the first argument and this UIViewRoot instance as the second argument.
197              */
198             FacesContext facesContext = FacesContext.getCurrentInstance();
199             facesContext.getApplication().publishEvent(facesContext, 
200                     PreDestroyViewMapEvent.class, facesContext.getViewRoot());
201             
202             super.clear();
203         }
204         
205     }
206 
207 }