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.menu;
20
21 import java.lang.reflect.Array;
22
23 import java.util.Iterator;
24 import java.util.List;
25
26 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
27
28 /**
29 * Code specific to a Menu Model's GroupNode.
30 *
31 */
32
33 public class GroupNode extends MenuNode
34 {
35 /**
36 * Constructs a GroupNode
37 */
38 public GroupNode()
39 {
40 super();
41 }
42
43 /**
44 * Called by the Default ActionListener
45 * when a menu node is clicked/selected.
46 *
47 * @return String outcome or viewId used
48 * during a POST for navigation.
49 */
50 @Override
51 public String doAction()
52 {
53 // Call the doAction method of my idref node
54 return getRefNode().doAction();
55 }
56
57 /**
58 * Get the Destination URL of a page for a
59 * GET.
60 *
61 * @return String URL of a page.
62 */
63 @Override
64 public String getDestination()
65 {
66 // Call the getDestination method of my idref node
67 return getRefNode().getDestination();
68 }
69
70 /**
71 * Sets the idref of the node.
72 *
73 * The value of this attribute is an "id" of another node
74 * This tells the pointing node where to obtain its viewId and
75 * takes precedence (and will replace) the pointing nodes viewId,
76 * if one exists. This should point to a node of the same style,
77 * e.g. actionNode points to actionNode.
78 *
79 * @param idref - String name pointing to the "id" of another node
80 */
81 public void setIdRef(String idref)
82 {
83 _idref = idref;
84
85 // Create a list of idref's for easier access
86 if (_idref != null)
87 _makeIdRefList (idref);
88 }
89
90 /**
91 * Get the node whose id matches this node's
92 * idref attribute value.
93 *
94 * @return the MenuNode whose id matches this
95 * node's idref attribute value.
96 */
97 @Override
98 public MenuNode getRefNode()
99 {
100 MenuNode refNode = null;
101
102 // create one if it does not exist
103 // should not happen, but can't hurt
104 if (_idrefList == null)
105 {
106 String idref = getIdRef();
107 _makeIdRefList(idref);
108 }
109
110 // Get idrefList
111 String[] idrefList = _getIdRefList();
112
113 // get group node's children
114 List<MenuNode> children = getChildren();
115
116 // Traverse the list. Do the following:
117 // o get Node from Model's hashMap of nodes and ids
118 // o check attributes (rendered, disabled, readOnly)
119 // o if they are ok, return the node
120 for (int i=0; i < Array.getLength(idrefList); i++)
121 {
122 Iterator<MenuNode> childIter = children.iterator();
123
124 // All node "id" attribute values had the node's
125 // system hashcode id appended to the id when
126 // placed in the model's idNodeMap.
127 //
128 // Each id in the idreflist of a group node does
129 // NOT have this node sys id appended it to it
130 // and needs to or we won't find the group's
131 // ref node.
132 //
133 // Since group nodes can only point to one of
134 // its children, we iterate through them, get
135 // their sys id and append it to idref until
136 // we find a match (or not).
137 while (childIter.hasNext())
138 {
139 MenuNode childNode = childIter.next();
140 String modelId = childNode.getModelId();
141
142 // Need to append mode's sys id here to create a
143 // unique id.
144 String refNodeId = idrefList[i] + modelId;
145
146 refNode = (MenuNode) getRootModel().getNode(refNodeId);
147
148 // if nothing found, move on to the next child
149 if (refNode != null)
150 break;
151 }
152
153 if (refNode == null)
154 continue;
155
156 // Check the attributes of the found node
157 if ( !refNode.getRendered()
158 || refNode.getDisabled()
159 || refNode.getReadOnly()
160 || !refNode.getVisible()
161 )
162 {
163 refNode = null;
164 continue;
165 }
166
167 // Ok, we have a valid RefNode
168 break;
169 }
170
171 // If no valid node is found,
172 // log an error
173 if (refNode == null)
174 {
175 _LOG.severe("GroupNode " + getLabel() + " refers to no valid node.\n");
176 return null;
177 }
178
179 return refNode;
180 }
181
182 /**
183 * Get the id of the node referred to by
184 * the idref attribute of this node.
185 *
186 * @return String id of the node referred
187 * to by the idref attribure of
188 * this node.
189 */
190 public String getIdRef()
191 {
192 return _idref;
193 }
194
195 public String[] getIdRefListProperty()
196 {
197 return _idrefList;
198 }
199
200 @Override
201 public MenuNode getThreadSafeCopy()
202 {
203 return new ImmutableGroupNode(this);
204 }
205
206 /* =============================================================
207 * Private methods
208 * =============================================================*/
209
210 /**
211 * _getIdRefList. gets the list of idrefs for this node.
212 *
213 * @return String[] list of idrefs for this node.
214 */
215 private String[] _getIdRefList()
216 {
217 return _idrefList;
218 }
219
220 /**
221 * Make a list of idref entries from the nodes String
222 * of idref's.
223 *
224 * This should only be called from the node's setIdRef
225 * method. So if it is called more than once (highly
226 * unlikely), simply empty out the previous contents.
227 *
228 * @param entries - String of String entries
229 *
230 */
231 private void _makeIdRefList (String entries)
232 {
233 _idrefList = entries.trim().split("\\s+");
234 }
235
236 private String _idref = null;
237 private String[] _idrefList = null;
238
239 private final static TrinidadLogger _LOG =
240 TrinidadLogger.createTrinidadLogger(GroupNode.class);
241 }