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.trinidad.model;
20
21 import java.beans.IntrospectionException;
22
23 import java.util.HashMap;
24 import java.util.Map;
25
26 import javax.faces.context.FacesContext;
27 import javax.faces.el.PropertyResolver;
28
29 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
30
31
32 /**
33 * Creates a MenuModel from a TreeModel where nodes in the treeModel contain
34 * viewId information.
35 * <p>
36 * Each node must have either a bean getter method or a Map property
37 * that returns a viewId. There are several restrictions on the data:
38 * <ul>
39 * <li>The nodes in the tree must either be all beans or all maps,
40 * but not a mix of beans and maps.
41 * <li>The viewId of a node can be null, but if set it must be unique.
42 * <li>The tree cannot be mutable.
43 * </ul>
44 * The getFocusPath method
45 * <ul>
46 * <li>gets the current viewId by calling
47 * FacesContext.getCurrentInstance().getViewRoot().getViewId()
48 * <li> compares the current viewId with the viewId's in
49 * the nodes of the tree
50 * <li>returns the path to the node with the current viewId or null if the current viewId can't be found
51 * </ul>
52 * <p>
53 * Assuming that NavigationTree is a tree of beans with a vieId getter, an
54 * example of creating a MenuModel with this class might look like:
55 * <pre><code>
56 * CollectionModel collectionModel = ModelUtils.toCollectionModel(new NavigationTree());
57 * TreeModel treeModel = new ChildPropertyTreeModel(collectionModel, "children");
58 * MenuModel menuModel = new ViewIdPropertyMenuModel(treeModel, "viewId");
59 * </code></pre>
60 */
61 // TODO - support for mutable trees?
62 public class ViewIdPropertyMenuModel extends BaseMenuModel
63 {
64 /**
65 * No-arg constructor for use with managed-beans.
66 * Must call the {@link #setViewIdProperty} and
67 * {@link #setWrappedData} methods after constructing this instance.
68 */
69 public ViewIdPropertyMenuModel()
70 {
71 super();
72 _focusPathMap = new HashMap<Object, Object>();
73 }
74 /**
75 *
76 * @param instance a treeModel. This object will be passed to
77 * {@link ModelUtils#toTreeModel}
78 * @param viewIdProperty the property to use to retrieve a viewId
79 * from a node in the tree
80 * @throws IntrospectionException
81 */
82 public ViewIdPropertyMenuModel(Object instance, String viewIdProperty)
83 throws IntrospectionException
84 {
85 super(instance);
86 _focusPathMap = new HashMap<Object, Object>();
87 setViewIdProperty(viewIdProperty);
88 setWrappedData(instance);
89 }
90
91 @Override
92 public void setWrappedData(Object data)
93 {
94 super.setWrappedData(data);
95 Object oldPath = getRowKey();
96
97 //set the focus path map
98 _focusPathMap.clear();
99 setRowKey(null);
100 FacesContext context = FacesContext.getCurrentInstance();
101 _addToMap(context, this, _focusPathMap, getViewIdProperty());
102 setRowKey(oldPath);
103 }
104
105 /**
106 * Returns the rowKey to the current viewId.
107 * <p>
108 *
109 * The getFocusRowKey method
110 * <ul>
111 * <li>gets the current viewId by calling
112 * FacesContext.getCurrentInstance().getViewRoot().getViewId()
113 * <li> compares the current viewId with the viewId's in
114 * the nodes of the tree
115 * <li>returns the rowKey to the node with the current viewId or null
116 * if the current viewId can't be found
117 * </ul>
118 *
119 * @return the rowKey to the node with the current viewId or null if the current viewId can't be found
120 */
121 @Override
122 public Object getFocusRowKey()
123 {
124 String currentViewId = getCurrentViewId();
125 Object focusPath = _focusPathMap.get(currentViewId);
126 return focusPath;
127 }
128
129 /**
130 * Maps the focusPath returned when the viewId is newViewId
131 * to the focusPath returned when the viewId is aliasedViewId.
132 * This allows view id's not in the treeModel to be mapped
133 * to a focusPath.
134 * @param newViewId the view id to add a focus path for
135 * @param aliasedViewId the view id to use to get the focusPath to use for newViewId
136 */
137 public void addViewId(
138 String newViewId,
139 String aliasedViewId
140 )
141 {
142 Object focusPath = _focusPathMap.get(aliasedViewId);
143 if (focusPath != null)
144 {
145 _focusPathMap.put(newViewId, focusPath);
146 }
147 }
148
149 /**
150 * Gets the property to use to retrieve a viewId
151 * from a node in the tree
152 */
153 public String getViewIdProperty()
154 {
155 return _viewIdProperty;
156 }
157
158 /**
159 * Sets the property to use to retrieve a viewId
160 * from a node in the tree
161 */
162 public void setViewIdProperty(String viewIdProperty)
163 {
164 _viewIdProperty = viewIdProperty;
165 }
166
167 /**
168 * Returns the current viewId.
169 * <p>
170 *
171 *
172 * @return the current viewId or null if the current viewId can't be found
173 */
174
175 protected String getCurrentViewId()
176 {
177 String currentViewId =
178 FacesContext.getCurrentInstance().getViewRoot().getViewId();
179
180 return currentViewId;
181 }
182
183
184 private static void _addToMap(
185 FacesContext context,
186 TreeModel tree,
187 Map<Object, Object> focusPathMap,
188 String viewIdProperty
189 )
190 {
191 for ( int i = 0; i < tree.getRowCount(); i++)
192 {
193 tree.setRowIndex(i);
194 if (viewIdProperty != null)
195 {
196 Object focusPath = tree.getRowKey();
197 Object data = tree.getRowData();
198 PropertyResolver resolver =
199 context.getApplication().getPropertyResolver();
200 Object viewIdObject = resolver.getValue(data, viewIdProperty);
201 focusPathMap.put(viewIdObject, focusPath);
202 }
203 else
204 {
205 _LOG.warning("NULL_VIEWID");
206 }
207
208 if (tree.isContainer() && !tree.isContainerEmpty())
209 {
210 tree.enterContainer();
211 _addToMap(context, tree, focusPathMap, viewIdProperty);
212 tree.exitContainer();
213 }
214
215 }
216 }
217
218
219 private final Map<Object, Object> _focusPathMap;
220 private String _viewIdProperty = null;
221
222
223
224 static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(ViewIdPropertyMenuModel.class);
225 }