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.application.pss;
20  
21  import org.apache.myfaces.shared_impl.util.ClassUtils;
22  
23  import javax.faces.component.UIViewRoot;
24  import javax.faces.component.UIComponent;
25  import javax.faces.context.FacesContext;
26  import java.util.*;
27  
28  /**
29   * @author Martin Haimberger
30   */
31  public class PartialTreeStructureManager
32  {
33      public static final String PARTIAL_STATE_CLASS_IDS = PartialTreeStructureManager.class.getName() + ".PARTIAL_STATE_MANAGER_COMPONENT_IDS";
34      
35      //Why wasn't this here ???
36      private FacesContext _facesContext = null;
37  
38      public PartialTreeStructureManager(FacesContext facesContext)
39      {
40          _facesContext = facesContext;
41      }
42  
43      public Object buildTreeStructureToSave(UIViewRoot viewRoot, FacesContext facesContext)
44      {
45          Object savedStateTree = viewRoot.processSaveState(facesContext);
46          if (viewRoot instanceof UIViewRootWrapper) {
47              // the first call ... all components have to be saved in the template
48             return internalBuildInitalTreeStructureToSave(viewRoot,facesContext, savedStateTree,0);
49          }
50          else return internalBuildTreeStructureToSave(viewRoot,facesContext, savedStateTree,0);
51      }
52  
53      private TreeStructComponent internalBuildInitalTreeStructureToSave(UIComponent component,FacesContext facesContext, Object state, int childIndex)
54      {
55  
56          Object myState = ((Object[])state)[0];
57          Map facetStateMap = (Map)((Object[])state)[1];
58          List childrenStateList = (List)((Object[])state)[2];
59  
60          TreeStructComponent structComp = new TreeStructComponent(convertStringToComponentClassId(facesContext,component.getClass().getName()),
61                                                                        component.getId(),myState,component.isTransient());
62  
63          //children
64          if (component.getChildCount() > 0)
65          {
66              List childList = component.getChildren();
67              List structChildList = new ArrayList();
68              for (int i = 0, len = childList.size(); i < len; i++)
69              {
70                  UIComponent child = (UIComponent)childList.get(i);
71                 if (!child.isTransient())
72                 {
73  
74                      TreeStructComponent structChild = internalBuildInitalTreeStructureToSave(child,facesContext,childrenStateList != null ? childrenStateList.get(childIndex++):null,0);
75                      structChildList.add(structChild);
76                  }
77                  else
78                 {
79  
80                     child.setTransient(false);
81                     TreeStructComponent structChild = internalBuildInitalTreeStructureToSave(child,facesContext,child.processSaveState(facesContext),0);
82                     structChildList.add(structChild);
83                     child.setTransient(true);
84  
85                 }
86              }
87              TreeStructComponent[] childArray = (TreeStructComponent[])structChildList.toArray(new TreeStructComponent[structChildList.size()]);
88              structComp.setChildren(childArray);
89          }
90  
91          //facets
92          Map facetMap = component.getFacets();
93          if (!facetMap.isEmpty())
94          {
95              List structFacetList = new ArrayList();
96              for (Iterator it = facetMap.entrySet().iterator(); it.hasNext(); )
97              {
98                  Map.Entry entry = (Map.Entry)it.next();
99                  UIComponent child = (UIComponent)entry.getValue();
100                 String facetName = (String)entry.getKey();
101                 if (!child.isTransient())
102                 {
103 
104                     TreeStructComponent structChild = internalBuildInitalTreeStructureToSave(child,facesContext,facetStateMap.get(facetName),0);
105                     structFacetList.add(new Object[] {facetName, structChild});
106                 }
107                 else
108                {
109                    // this is a transient Component ... save it anyway
110                    child.setTransient(false);
111                    TreeStructComponent structChild = internalBuildInitalTreeStructureToSave(child,facesContext,child.processSaveState(facesContext),0);
112                    structFacetList.add(new Object[] {facetName, structChild});
113                    child.setTransient(true);
114                }
115             }
116             Object[] facetArray = structFacetList.toArray(new Object[structFacetList.size()]);
117             structComp.setFacets(facetArray);
118         }
119 
120         return structComp;
121     }
122 
123     private TreeStructComponent internalBuildTreeStructureToSave(UIComponent component,FacesContext facesContext, Object state, int childIndex)
124     {
125 
126         Object myState = ((Object[])state)[0];
127         Map facetStateMap = (Map)((Object[])state)[1];
128         List childrenStateList = (List)((Object[])state)[2];
129 
130         TreeStructComponent structComp = new TreeStructComponent(convertStringToComponentClassId(facesContext,component.getClass().getName()),
131                                                                       component.getId(),myState,component.isTransient());
132 
133         //children
134         if (component.getChildCount() > 0)
135         {
136             List childList = component.getChildren();
137             List structChildList = new ArrayList();
138             for (int i = 0, len = childList.size(); i < len; i++)
139             {
140                 UIComponent child = (UIComponent)childList.get(i);
141                if (!child.isTransient())
142                {
143 
144                     TreeStructComponent structChild = internalBuildTreeStructureToSave(child,facesContext,childrenStateList != null ? childrenStateList.get(childIndex++):null,0);
145                     structChildList.add(structChild);
146                 }
147             }
148             TreeStructComponent[] childArray = (TreeStructComponent[])structChildList.toArray(new TreeStructComponent[structChildList.size()]);
149             structComp.setChildren(childArray);
150         }
151 
152         //facets
153         Map facetMap = component.getFacets();
154         if (!facetMap.isEmpty())
155         {
156             List structFacetList = new ArrayList();
157             for (Iterator it = facetMap.entrySet().iterator(); it.hasNext(); )
158             {
159                 Map.Entry entry = (Map.Entry)it.next();
160                 UIComponent child = (UIComponent)entry.getValue();
161                 String facetName = (String)entry.getKey();
162                 if (!child.isTransient())
163                 {
164 
165                     TreeStructComponent structChild = internalBuildTreeStructureToSave(child,facesContext,facetStateMap.get(facetName),0);
166                     structFacetList.add(new Object[] {facetName, structChild});
167                 }
168 
169             }
170             Object[] facetArray = structFacetList.toArray(new Object[structFacetList.size()]);
171             structComp.setFacets(facetArray);
172         }
173 
174         return structComp;
175     }
176 
177 
178 
179     public UIViewRoot restoreTreeStructure(FacesContext facesContext,Object treeStructRoot)
180     {
181         if (treeStructRoot instanceof TreeStructComponent)
182         {
183             return (UIViewRoot)internalRestoreTreeStructure((TreeStructComponent)treeStructRoot,facesContext);
184         }
185         else
186         {
187             throw new IllegalArgumentException("TreeStructure of type " + treeStructRoot.getClass().getName() + " is not supported.");
188         }
189     }
190 
191     private UIComponent internalRestoreTreeStructure(TreeStructComponent treeStructComp,FacesContext facesContext)
192     {
193         String compClass = convertComponentClassIdToString(facesContext,treeStructComp.getComponentClass());
194         String compId = treeStructComp.getComponentId();
195         UIComponent component = (UIComponent) ClassUtils.newInstance(compClass);
196         component.setId(compId);
197         component.setTransient(treeStructComp.isTransient());
198 
199         //children
200         TreeStructComponent[] childArray = treeStructComp.getChildren();
201         if (childArray != null)
202         {
203             List childList = component.getChildren();
204             for (int i = 0, len = childArray.length; i < len; i++)
205             {
206                 UIComponent child = internalRestoreTreeStructure(childArray[i],facesContext);
207                 childList.add(child);
208             }
209         }
210 
211         //facets
212         Object[] facetArray = treeStructComp.getFacets();
213         if (facetArray != null)
214         {
215             Map facetMap = component.getFacets();
216             for (int i = 0, len = facetArray.length; i < len; i++)
217             {
218                 TreeStructComponent structChild = (TreeStructComponent)((Object[])facetArray[i])[1];
219                 String facetName = (String)((Object[])facetArray[i])[0];
220                 UIComponent child = internalRestoreTreeStructure(structChild,facesContext);
221                 facetMap.put(facetName, child);
222             }
223         }
224 
225 
226         return component;
227     }
228 
229 
230 
231     private String convertComponentClassIdToString(FacesContext facesContext,Integer classId){
232         Object[] idmaps = (Object[])facesContext.getExternalContext().getApplicationMap().get(PARTIAL_STATE_CLASS_IDS);
233 
234         if ( idmaps== null)
235         {
236             // create on
237             idmaps = new Object[2];
238             // contains the Classid as Map
239             idmaps[0] = new HashMap();
240             idmaps[1] = new HashMap();
241             facesContext.getExternalContext().getApplicationMap().put(PARTIAL_STATE_CLASS_IDS,idmaps);
242         }
243         return (String)((HashMap)idmaps[0]).get(classId);
244     }
245 
246     private Integer convertStringToComponentClassId(FacesContext facesContext,String stringToConvert){
247 
248         // if it was the first time and the wrapper was use ... use the original UIViewRoot
249 
250         if (stringToConvert.equalsIgnoreCase("org.apache.myfaces.application.pss.UIViewRootWrapper")) {
251             stringToConvert = "javax.faces.component.UIViewRoot";
252         }
253 
254         Object[] idmaps = (Object[])facesContext.getExternalContext().getApplicationMap().get(PARTIAL_STATE_CLASS_IDS);
255 
256         if ( idmaps== null)
257         {
258             // create on
259             idmaps = new Object[2];
260             // contains the Classid as Map
261             idmaps[0] = new HashMap();
262             idmaps[1] = new HashMap();
263         }
264         Integer idInMap = (Integer)((HashMap)idmaps[1]).get(stringToConvert);
265         HashMap idToStringMap=((HashMap)idmaps[0]);
266         HashMap stringToIdMap=((HashMap)idmaps[1]);
267 
268         if (idInMap == null )
269         {
270             // this type is not jet registerd ... register now
271             Integer id = new Integer(stringToIdMap.size());
272 
273             stringToIdMap.put(stringToConvert,id);
274             idToStringMap.put(id,stringToConvert);
275         }
276         facesContext.getExternalContext().getApplicationMap().put(PARTIAL_STATE_CLASS_IDS,idmaps);
277         return (Integer)stringToIdMap.get(stringToConvert);
278     }
279 
280 
281 }