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.cdi.view;
20  
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.HashSet;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  import javax.enterprise.inject.spi.BeanManager;
28  import javax.faces.context.FacesContext;
29  import org.apache.myfaces.cdi.util.CDIUtils;
30  import org.apache.myfaces.cdi.util.ContextualInstanceInfo;
31  
32  /**
33   *
34   * @author Leonardo Uribe
35   */
36  public class ViewScopeCDIMap implements Map<String, Object>
37  {
38      private String _viewScopeId;
39      
40      private ViewScopeContextualStorage storage;
41  
42      public ViewScopeCDIMap(FacesContext facesContext)
43      {
44          BeanManager beanManager = CDIUtils.getBeanManager(facesContext.getExternalContext());
45  
46          ViewScopeBeanHolder bean = CDIUtils.lookup(beanManager, ViewScopeBeanHolder.class);
47  
48          // 1. get a new view scope id
49          _viewScopeId = bean.generateUniqueViewScopeId();
50  
51          storage = bean.getContextualStorage(beanManager, _viewScopeId);
52      }
53      
54      public ViewScopeCDIMap(FacesContext facesContext, String viewScopeId)
55      {
56          BeanManager beanManager = CDIUtils.getBeanManager(facesContext.getExternalContext());
57  
58          ViewScopeBeanHolder bean = CDIUtils.lookup(beanManager, ViewScopeBeanHolder.class);
59  
60          // 1. get a new view scope id
61          _viewScopeId = viewScopeId;
62  
63          storage = bean.getContextualStorage(beanManager, _viewScopeId);
64      }
65      
66      private ViewScopeContextualStorage getStorage()
67      {
68          if (storage != null && !storage.isActive())
69          {
70              storage = null;
71          }
72          if (storage == null)
73          {
74              FacesContext facesContext = FacesContext.getCurrentInstance();
75              BeanManager beanManager = CDIUtils.getBeanManager(facesContext.getExternalContext());
76  
77              ViewScopeBeanHolder bean = CDIUtils.lookup(beanManager, ViewScopeBeanHolder.class);
78              
79              storage = bean.getContextualStorage(beanManager, _viewScopeId);
80          }
81          return storage;
82      }
83      
84      private Map<String, Object> getNameBeanKeyMap()
85      {
86          return getStorage().getNameBeanKeyMap();
87      }
88      
89      private Map<Object, ContextualInstanceInfo<?>> getCreationalContextInstances()
90      {
91          return getStorage().getStorage();
92      }
93      
94      public String getViewScopeId()
95      {
96          return _viewScopeId;
97      }
98      
99      @Override
100     public int size()
101     {
102         return this.getNameBeanKeyMap().size();
103     }
104 
105     @Override
106     public boolean isEmpty()
107     {
108         return this.getNameBeanKeyMap().isEmpty();
109     }
110 
111     @Override
112     public boolean containsKey(Object key)
113     {
114         return this.getNameBeanKeyMap().containsKey(key);
115     }
116 
117     @Override
118     public boolean containsValue(Object value)
119     {
120         if (value != null)
121         {
122             for (Map.Entry<Object, ContextualInstanceInfo<?>> entry : getCreationalContextInstances().entrySet())
123             {
124                 if (entry.getValue() != null && value.equals(entry.getValue().getContextualInstance()))
125                 {
126                     return true;
127                 }
128             }
129         }
130         return false;
131     }
132 
133     @Override
134     public Object get(Object key)
135     {
136         Object beanKey = this.getNameBeanKeyMap().get(key);
137         if (beanKey != null)
138         {
139             ContextualInstanceInfo<?> info = this.getCreationalContextInstances().get(beanKey);
140             return info == null ? null : info.getContextualInstance();
141         }
142         return null;
143     }
144 
145     @Override
146     public Object put(String key, Object value)
147     {
148         Object beanKey = new ViewScopeContextualKey(key);
149         this.getNameBeanKeyMap().put(key, beanKey);
150         ContextualInstanceInfo info = new ContextualInstanceInfo();
151         info.setContextualInstance(value);
152         return this.getCreationalContextInstances().put(beanKey, info);
153     }
154 
155     @Override
156     public Object remove(Object key)
157     {
158         Object beanKey = this.getNameBeanKeyMap().remove(key);
159         ContextualInstanceInfo info = this.getCreationalContextInstances().remove(beanKey);
160         return info == null ? null : info.getContextualInstance();
161     }
162 
163     @Override
164     public void putAll(Map<? extends String, ? extends Object> m)
165     {
166         for (Map.Entry<? extends String, ? extends Object> entry : m.entrySet())
167         {
168             put(entry.getKey(), entry.getValue());
169         }
170     }
171 
172     @Override
173     public void clear()
174     {
175         boolean destroyed = false;
176         // If the scope was already destroyed through an invalidateSession(), the storage instance
177         // that is holding this map could be obsolete, so we need to grab the right instance from
178         // the bean holder.
179         FacesContext facesContext = FacesContext.getCurrentInstance();
180         if (facesContext != null)
181         {
182             BeanManager beanManager = CDIUtils.getBeanManager(facesContext.getExternalContext());
183 
184             if (beanManager != null)
185             {
186                 ViewScopeBeanHolder bean = CDIUtils.lookup(beanManager, ViewScopeBeanHolder.class);
187                 if (bean != null)
188                 {
189                     ViewScopeContextualStorage st = bean.getContextualStorage(beanManager, _viewScopeId);
190                     if (st != null)
191                     {
192                         ViewScopeContextImpl.destroyAllActive(st);
193                         storage = null;
194                         destroyed = true;
195                     }
196                 }
197             }
198         }
199         if (!destroyed)
200         {
201             ViewScopeContextImpl.destroyAllActive(storage);
202         }
203     }
204 
205     @Override
206     public Set<String> keySet()
207     {
208         return this.getNameBeanKeyMap().keySet();
209     }
210 
211     @Override
212     public Collection<Object> values()
213     {
214         List<Object> values = new ArrayList<Object>(this.getNameBeanKeyMap().size());
215         for (Map.Entry<String, Object> entry : this.getNameBeanKeyMap().entrySet())
216         {
217             if (entry.getValue() != null)
218             {
219                 ContextualInstanceInfo info = this.getCreationalContextInstances().get(entry.getValue());
220                 if (info != null)
221                 {
222                     values.add(info.getContextualInstance());
223                 }
224             }
225         }
226         return values;
227     }
228 
229     @Override
230     public Set<Entry<String, Object>> entrySet()
231     {
232         Set<Entry<String, Object>> values = new HashSet<Entry<String, Object>>();
233         for (Map.Entry<String, Object> entry : this.getNameBeanKeyMap().entrySet())
234         {
235             if (entry.getValue() != null)
236             {
237                 ContextualInstanceInfo info = this.getCreationalContextInstances().get(entry.getValue());
238                 if (info != null)
239                 {
240                     values.add(new EntryWrapper(entry));
241                 }
242             }
243         }
244         return values;
245     }
246     
247     private class EntryWrapper<String, Object> implements Entry<String, Object>
248     {
249         private Map.Entry<String, Object> entry;
250         
251         public EntryWrapper(Map.Entry<String, Object> entry)
252         {
253             this.entry = entry;
254         }
255 
256         @Override
257         public String getKey()
258         {
259             return entry.getKey();
260         }
261 
262         @Override
263         public Object getValue()
264         {
265             ContextualInstanceInfo<?> info = getCreationalContextInstances().get(entry.getValue());
266             return (Object) (info == null ? null : info.getContextualInstance());
267         }
268 
269         @Override
270         public Object setValue(Object value)
271         {
272             ContextualInstanceInfo info = getCreationalContextInstances().get(entry.getValue());
273             Object oldValue = null;
274             if (info != null)
275             {
276                 info.setContextualInstance(value);
277             }
278             else
279             {
280                 info = new ContextualInstanceInfo();
281                 info.setContextualInstance(value);
282                 getCreationalContextInstances().put(entry.getValue(), info);
283             }
284             return oldValue;
285         }
286     }
287 }