%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.jetspeed.portalsite.impl.MenuImpl |
|
|
1 | /* |
|
2 | * Licensed to the Apache Software Foundation (ASF) under one or more |
|
3 | * contributor license agreements. See the NOTICE file distributed with |
|
4 | * this work for additional information regarding copyright ownership. |
|
5 | * The ASF licenses this file to You under the Apache License, Version 2.0 |
|
6 | * (the "License"); you may not use this file except in compliance with |
|
7 | * the License. You may obtain a copy of the License at |
|
8 | * |
|
9 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
10 | * |
|
11 | * Unless required by applicable law or agreed to in writing, software |
|
12 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
14 | * See the License for the specific language governing permissions and |
|
15 | * limitations under the License. |
|
16 | */ |
|
17 | package org.apache.jetspeed.portalsite.impl; |
|
18 | ||
19 | import java.util.ArrayList; |
|
20 | import java.util.HashSet; |
|
21 | import java.util.Iterator; |
|
22 | import java.util.List; |
|
23 | import java.util.ListIterator; |
|
24 | import java.util.Locale; |
|
25 | import java.util.Set; |
|
26 | import java.util.regex.Matcher; |
|
27 | import java.util.regex.Pattern; |
|
28 | ||
29 | import org.apache.jetspeed.om.common.GenericMetadata; |
|
30 | import org.apache.jetspeed.om.folder.Folder; |
|
31 | import org.apache.jetspeed.om.folder.MenuDefinition; |
|
32 | import org.apache.jetspeed.om.folder.MenuExcludeDefinition; |
|
33 | import org.apache.jetspeed.om.folder.MenuIncludeDefinition; |
|
34 | import org.apache.jetspeed.om.folder.MenuOptionsDefinition; |
|
35 | import org.apache.jetspeed.om.folder.MenuSeparatorDefinition; |
|
36 | import org.apache.jetspeed.om.page.Page; |
|
37 | import org.apache.jetspeed.page.document.Node; |
|
38 | import org.apache.jetspeed.page.document.NodeNotFoundException; |
|
39 | import org.apache.jetspeed.portalsite.Menu; |
|
40 | import org.apache.jetspeed.portalsite.MenuElement; |
|
41 | import org.apache.jetspeed.portalsite.MenuOption; |
|
42 | import org.apache.jetspeed.portalsite.PortalSiteRequestContext; |
|
43 | import org.apache.jetspeed.portalsite.menu.DefaultMenuDefinition; |
|
44 | import org.apache.jetspeed.portalsite.menu.DefaultMenuOptionsDefinition; |
|
45 | import org.apache.jetspeed.portalsite.view.SiteView; |
|
46 | ||
47 | /** |
|
48 | * This class implements the portal-site menu elements |
|
49 | * constructed and returned to decorators. |
|
50 | * |
|
51 | * @author <a href="mailto:rwatler@apache.org">Randy Watler</a> |
|
52 | * @version $Id: MenuImpl.java 516448 2007-03-09 16:25:47Z ate $ |
|
53 | */ |
|
54 | public class MenuImpl extends MenuElementImpl implements Menu, Cloneable |
|
55 | { |
|
56 | /** |
|
57 | * definition - menu definition |
|
58 | */ |
|
59 | private MenuDefinition definition; |
|
60 | ||
61 | /** |
|
62 | * elements - ordered list of menu elements that |
|
63 | * make up this instaniated menu |
|
64 | */ |
|
65 | private List elements; |
|
66 | ||
67 | /** |
|
68 | * elementRelative - flag that indicates whether any relative paths |
|
69 | * dependent on the current page in context were |
|
70 | * referenced while constructing menu elements: |
|
71 | * requires request, not session, caching |
|
72 | */ |
|
73 | private boolean elementRelative; |
|
74 | ||
75 | /** |
|
76 | * MenuImpl - request/session context dependent constructor |
|
77 | * |
|
78 | * @param parent containing menu implementation |
|
79 | * @param definition menu definition |
|
80 | * @param context request context |
|
81 | * @param menus related menu definition names set |
|
82 | */ |
|
83 | public MenuImpl(MenuImpl parent, MenuDefinition definition, PortalSiteRequestContextImpl context, Set menus) |
|
84 | { |
|
85 | 0 | super(parent); |
86 | 0 | this.definition = definition; |
87 | ||
88 | // get site view from context |
|
89 | 0 | SiteView view = ((PortalSiteSessionContextImpl)context.getSessionContext()).getSiteView(); |
90 | 0 | if (view != null) |
91 | { |
|
92 | // define menu node for titles and metadata if options |
|
93 | // specifies a single visible page or folder proxy |
|
94 | 0 | String options = definition.getOptions(); |
95 | 0 | Node optionProxy = null; |
96 | 0 | if ((options != null) && (options.indexOf(',') == -1)) |
97 | { |
|
98 | try |
|
99 | { |
|
100 | 0 | optionProxy = view.getNodeProxy(options, context.getPage(), true, class="keyword">true); |
101 | } |
|
102 | 0 | catch (NodeNotFoundException nnfe) |
103 | { |
|
104 | } |
|
105 | 0 | catch (SecurityException se) |
106 | { |
|
107 | 0 | } |
108 | 0 | if (optionProxy != null) |
109 | { |
|
110 | 0 | setNode(optionProxy); |
111 | } |
|
112 | } |
|
113 | ||
114 | // construct menu elements from menu definition |
|
115 | // or nested menu definition elements; note that |
|
116 | // menu elements override menu options attribute |
|
117 | 0 | if ((definition.getMenuElements() == null) || definition.getMenuElements().isEmpty()) |
118 | { |
|
119 | // if options optionProxy is a single folder, force |
|
120 | // options to include all folder children if not to |
|
121 | // be expanded with paths and depth inclusion is |
|
122 | // specified |
|
123 | 0 | List overrideOptionProxies = null; |
124 | 0 | if (optionProxy != null) |
125 | { |
|
126 | 0 | if ((optionProxy instanceof Folder) && !definition.isPaths() && (definition.getDepth() != 0)) |
127 | { |
|
128 | // assemble folder children path using wildcard |
|
129 | 0 | String folderChildrenPath = null; |
130 | 0 | if (!options.endsWith(Folder.PATH_SEPARATOR)) |
131 | { |
|
132 | 0 | folderChildrenPath = options + Folder.PATH_SEPARATOR + "*"; |
133 | } |
|
134 | else |
|
135 | { |
|
136 | 0 | folderChildrenPath = options + "*"; |
137 | } |
|
138 | ||
139 | // override menu options with visible folder contents |
|
140 | // or create empty menu if no contents exist |
|
141 | 0 | List folderChildren = null; |
142 | try |
|
143 | { |
|
144 | 0 | folderChildren = view.getNodeProxies(folderChildrenPath, context.getPage(), true, class="keyword">true); |
145 | } |
|
146 | 0 | catch (NodeNotFoundException nnfe) |
147 | { |
|
148 | } |
|
149 | 0 | catch (SecurityException se) |
150 | { |
|
151 | 0 | } |
152 | 0 | if ((folderChildren != null) && !folderChildren.isEmpty()) |
153 | { |
|
154 | 0 | overrideOptionProxies = folderChildren; |
155 | } |
|
156 | else |
|
157 | { |
|
158 | 0 | return; |
159 | } |
|
160 | 0 | } |
161 | else |
|
162 | { |
|
163 | // override menu options with single folder/page/link |
|
164 | 0 | overrideOptionProxies = new ArrayList(1); |
165 | 0 | overrideOptionProxies.add(optionProxy); |
166 | } |
|
167 | ||
168 | // set relative element flag if options path is relative |
|
169 | 0 | this.elementRelative = (class="keyword">this.elementRelative || !options.startsWith(Folder.PATH_SEPARATOR)); |
170 | } |
|
171 | ||
172 | // menu defined only with menu definition options |
|
173 | 0 | this.elements = constructMenuElements(context, view, options, overrideOptionProxies, definition.getDepth(), definition.isPaths(), definition.isRegexp(), definition.getProfile(), definition.getOrder()); |
174 | 0 | } |
175 | else |
|
176 | { |
|
177 | // limit cyclic references to this menu if named and |
|
178 | // referencable as root menu instance |
|
179 | 0 | boolean menuNameReferenced = false; |
180 | 0 | if ((definition.getName() != null) && (parent == class="keyword">null)) |
181 | { |
|
182 | 0 | if (menus == null) |
183 | { |
|
184 | 0 | menus = new HashSet(4); |
185 | } |
|
186 | 0 | menuNameReferenced = menus.add(definition.getName()); |
187 | } |
|
188 | ||
189 | // process menu elements in chunks between separators: |
|
190 | // separators are included only if menu options are |
|
191 | // generated after the separator and include/exclude |
|
192 | // merge/filter operations apply to options bounded |
|
193 | // by separators |
|
194 | 0 | MenuSeparatorImpl separator = null; |
195 | 0 | List separatedElements = null; |
196 | ||
197 | // process each defined menu element |
|
198 | 0 | Iterator menuElementsIter = definition.getMenuElements().iterator(); |
199 | 0 | while (menuElementsIter.hasNext()) |
200 | { |
|
201 | 0 | Object menuElement = menuElementsIter.next(); |
202 | 0 | if (menuElement instanceof MenuOptionsDefinition) |
203 | { |
|
204 | // construct menu option elements from definition using |
|
205 | // defaults from menu definition as appropriate |
|
206 | 0 | MenuOptionsDefinition optionDefinition = (MenuOptionsDefinition)menuElement; |
207 | 0 | String locatorName = optionDefinition.getProfile(); |
208 | 0 | if (locatorName == null) |
209 | { |
|
210 | 0 | locatorName = definition.getProfile(); |
211 | } |
|
212 | 0 | String order = optionDefinition.getOrder(); |
213 | 0 | if (order == null) |
214 | { |
|
215 | 0 | order = definition.getOrder(); |
216 | } |
|
217 | 0 | List optionsAndMenus = constructMenuElements(context, view, optionDefinition.getOptions(), null, optionDefinition.getDepth(), optionDefinition.isPaths(), optionDefinition.isRegexp(), locatorName, order); |
218 | ||
219 | // append option and menu elements to current separator |
|
220 | // elements list |
|
221 | 0 | if (optionsAndMenus != null) |
222 | { |
|
223 | 0 | if (separatedElements == null) |
224 | { |
|
225 | 0 | separatedElements = optionsAndMenus; |
226 | } |
|
227 | else |
|
228 | { |
|
229 | 0 | appendMenuElements(optionsAndMenus, separatedElements); |
230 | } |
|
231 | } |
|
232 | 0 | } |
233 | 0 | else if (menuElement instanceof MenuSeparatorDefinition) |
234 | { |
|
235 | // append current separator and separated option/menu elements |
|
236 | // to menu elements list if at least one option/menu |
|
237 | // element exists: do not include disassociated separators in menu |
|
238 | 0 | if ((separatedElements != null) && !separatedElements.isEmpty()) |
239 | { |
|
240 | 0 | if (this.elements == null) |
241 | { |
|
242 | 0 | int initialSize = separatedElements.size(); |
243 | 0 | if (separator != null) |
244 | { |
|
245 | 0 | initialSize++; |
246 | } |
|
247 | 0 | this.elements = new ArrayList(initialSize); |
248 | } |
|
249 | 0 | if (separator != null) |
250 | { |
|
251 | 0 | this.elements.add(separator); |
252 | } |
|
253 | 0 | this.elements.addAll(separatedElements); |
254 | } |
|
255 | ||
256 | // construct new separator and reset separator |
|
257 | // and separator option/menu elements list |
|
258 | 0 | MenuSeparatorDefinition separatorDefinition = (MenuSeparatorDefinition)menuElement; |
259 | 0 | separator = new MenuSeparatorImpl(this, separatorDefinition); |
260 | 0 | if (separatedElements != null) |
261 | { |
|
262 | 0 | separatedElements.clear(); |
263 | } |
|
264 | 0 | } |
265 | 0 | else if (menuElement instanceof MenuDefinition) |
266 | { |
|
267 | // construct nested menu element from definition |
|
268 | 0 | MenuDefinition menuDefinition = (MenuDefinition)menuElement; |
269 | 0 | MenuImpl nestedMenu = new MenuImpl(this, menuDefinition, context, menus); |
270 | ||
271 | // append menu element to current separated elements list |
|
272 | 0 | if (separatedElements == null) |
273 | { |
|
274 | 0 | separatedElements = new ArrayList(1); |
275 | } |
|
276 | 0 | appendMenuElement(nestedMenu, separatedElements); |
277 | ||
278 | // set relative element flag if nested menu is relative |
|
279 | 0 | this.elementRelative = (class="keyword">this.elementRelative || nestedMenu.isElementRelative()); |
280 | 0 | } |
281 | 0 | else if (menuElement instanceof MenuIncludeDefinition) |
282 | { |
|
283 | // include or nest referenced menu definition |
|
284 | // assuming reference to menu is not cyclic |
|
285 | 0 | MenuIncludeDefinition includeDefinition = (MenuIncludeDefinition)menuElement; |
286 | 0 | if ((menus == null) || !menus.contains(includeDefinition.getName())) |
287 | { |
|
288 | // get named root menu from context, (menu may |
|
289 | // not exist in this context so failure to |
|
290 | // access menu is ignored) |
|
291 | 0 | MenuImpl includeMenu = null; |
292 | try |
|
293 | { |
|
294 | 0 | includeMenu = (MenuImpl)context.getMenu(includeDefinition.getName()); |
295 | } |
|
296 | 0 | catch (NodeNotFoundException nnfe) |
297 | { |
|
298 | } |
|
299 | 0 | catch (SecurityException se) |
300 | { |
|
301 | 0 | } |
302 | 0 | if (includeMenu != null) |
303 | { |
|
304 | // nest menu or include elements, clone required |
|
305 | // to support reparenting to this menu |
|
306 | 0 | if (includeDefinition.isNest()) |
307 | { |
|
308 | // nest menu instance |
|
309 | try |
|
310 | { |
|
311 | // clone menu and reparent |
|
312 | 0 | includeMenu = (MenuImpl)includeMenu.clone(); |
313 | 0 | includeMenu.setParentMenu(this); |
314 | ||
315 | // append menu element to current separated elements list |
|
316 | 0 | if (separatedElements == null) |
317 | { |
|
318 | 0 | separatedElements = new ArrayList(1); |
319 | } |
|
320 | 0 | appendMenuElement(includeMenu, separatedElements); |
321 | } |
|
322 | 0 | catch (CloneNotSupportedException cnse) |
323 | { |
|
324 | 0 | } |
325 | } |
|
326 | else |
|
327 | { |
|
328 | // include menu elements |
|
329 | 0 | if (!includeMenu.isEmpty()) |
330 | { |
|
331 | 0 | Iterator elementsIter = includeMenu.getElements().iterator(); |
332 | 0 | while (elementsIter.hasNext()) |
333 | { |
|
334 | 0 | MenuElementImpl includeElement = (MenuElementImpl)elementsIter.next(); |
335 | try |
|
336 | { |
|
337 | // clone menu element and reparent |
|
338 | 0 | includeElement = (MenuElementImpl)includeElement.clone(); |
339 | 0 | includeElement.setParentMenu(this); |
340 | ||
341 | // insert separators or options and menus |
|
342 | 0 | if (includeElement instanceof MenuSeparatorImpl) |
343 | { |
|
344 | // append current separator and separated option/menu elements |
|
345 | 0 | if ((separatedElements != null) && !separatedElements.isEmpty()) |
346 | { |
|
347 | 0 | if (this.elements == null) |
348 | { |
|
349 | 0 | int initialSize = separatedElements.size(); |
350 | 0 | if (separator != null) |
351 | { |
|
352 | 0 | initialSize++; |
353 | } |
|
354 | 0 | this.elements = new ArrayList(initialSize); |
355 | } |
|
356 | 0 | if (separator != null) |
357 | { |
|
358 | 0 | this.elements.add(separator); |
359 | } |
|
360 | 0 | this.elements.addAll(separatedElements); |
361 | } |
|
362 | ||
363 | // reset separator and separator option/menu elements list |
|
364 | // using separator menu element |
|
365 | 0 | separator = (MenuSeparatorImpl)includeElement; |
366 | 0 | if (separatedElements != null) |
367 | { |
|
368 | 0 | separatedElements.clear(); |
369 | } |
|
370 | } |
|
371 | else |
|
372 | { |
|
373 | // append menu element to current separated elements list |
|
374 | 0 | if (separatedElements == null) |
375 | { |
|
376 | 0 | separatedElements = new ArrayList(includeMenu.getElements().size()); |
377 | } |
|
378 | 0 | appendMenuElement(includeElement, separatedElements); |
379 | } |
|
380 | } |
|
381 | 0 | catch (CloneNotSupportedException cnse) |
382 | { |
|
383 | 0 | } |
384 | 0 | } |
385 | } |
|
386 | } |
|
387 | ||
388 | // set relative element flag if included menu is relative |
|
389 | 0 | this.elementRelative = (class="keyword">this.elementRelative || includeMenu.isElementRelative()); |
390 | } |
|
391 | } |
|
392 | 0 | } |
393 | 0 | else if (menuElement instanceof MenuExcludeDefinition) |
394 | { |
|
395 | // exclusion requires current separated elements |
|
396 | 0 | if ((separatedElements != null) && !separatedElements.isEmpty()) |
397 | { |
|
398 | // exclude top level referenced menu definition |
|
399 | // options assuming reference to menu is not cyclic |
|
400 | 0 | MenuExcludeDefinition excludeDefinition = (MenuExcludeDefinition)menuElement; |
401 | 0 | if ((menus == null) || !menus.contains(excludeDefinition.getName())) |
402 | { |
|
403 | // get named root menu from context, (menu may |
|
404 | // not exist in this context so failure to |
|
405 | // access menu is ignored) |
|
406 | 0 | MenuImpl excludeMenu = null; |
407 | try |
|
408 | { |
|
409 | 0 | excludeMenu = (MenuImpl)context.getMenu(excludeDefinition.getName()); |
410 | } |
|
411 | 0 | catch (NodeNotFoundException nnfe) |
412 | { |
|
413 | } |
|
414 | 0 | catch (SecurityException se) |
415 | { |
|
416 | 0 | } |
417 | 0 | if (excludeMenu != null) |
418 | { |
|
419 | // remove referenced menu options from current |
|
420 | // separated elements list |
|
421 | 0 | removeMenuElements(excludeMenu.getElements(), separatedElements); |
422 | ||
423 | // set relative element flag if excluded menu is relative |
|
424 | 0 | this.elementRelative = (class="keyword">this.elementRelative || excludeMenu.isElementRelative()); |
425 | } |
|
426 | } |
|
427 | } |
|
428 | } |
|
429 | 0 | } |
430 | ||
431 | // append last separator and separated option/menu elements |
|
432 | // to menu elements list if at least one option/menu |
|
433 | // element exists: do not include trailing separators |
|
434 | 0 | if ((separatedElements != null) && !separatedElements.isEmpty()) |
435 | { |
|
436 | 0 | if (this.elements == null) |
437 | { |
|
438 | // use the separated elements as the menu elements |
|
439 | // collection and insert the separator |
|
440 | 0 | this.elements = separatedElements; |
441 | 0 | if (separator != null) |
442 | { |
|
443 | 0 | this.elements.add(0, separator); |
444 | } |
|
445 | } |
|
446 | else |
|
447 | { |
|
448 | // copy into existing menu elements collection |
|
449 | 0 | if (separator != null) |
450 | { |
|
451 | 0 | this.elements.add(separator); |
452 | } |
|
453 | 0 | this.elements.addAll(separatedElements); |
454 | } |
|
455 | } |
|
456 | ||
457 | // restore referencing for this menu if limited |
|
458 | 0 | if (menuNameReferenced) |
459 | { |
|
460 | 0 | menus.remove(definition.getName()); |
461 | } |
|
462 | } |
|
463 | } |
|
464 | 0 | } |
465 | ||
466 | /** |
|
467 | * MenuImpl - request/session context dependent constructor |
|
468 | * |
|
469 | * @param definition menu definition |
|
470 | * @param context request context |
|
471 | * @param menus related menu definition names set |
|
472 | */ |
|
473 | public MenuImpl(MenuDefinition definition, PortalSiteRequestContextImpl context, Set menus) |
|
474 | { |
|
475 | 0 | this(null, definition, context, menus); |
476 | 0 | } |
477 | ||
478 | /** |
|
479 | * appendMenuElement - append to ordered list of unique menu |
|
480 | * option/menu elements |
|
481 | * |
|
482 | * @param appendMenuElement option/menu element to append |
|
483 | * @param menuElements option/menu element list |
|
484 | */ |
|
485 | private void appendMenuElement(MenuElementImpl appendMenuElement, List menuElements) |
|
486 | { |
|
487 | // make sure new menu element is unique and |
|
488 | // add to menu element list |
|
489 | 0 | if (appendMenuElement != null) |
490 | { |
|
491 | 0 | if (!menuElements.contains(appendMenuElement)) |
492 | { |
|
493 | 0 | menuElements.add(appendMenuElement); |
494 | } |
|
495 | } |
|
496 | 0 | } |
497 | ||
498 | /** |
|
499 | * appendMenuElements - append to ordered list of unique menu |
|
500 | * option/menu elements |
|
501 | * |
|
502 | * @param appendMenuElements option/menu element list to append |
|
503 | * @param menuElements option/menu element list |
|
504 | */ |
|
505 | private void appendMenuElements(List appendMenuElements, List menuElements) |
|
506 | { |
|
507 | // make sure new menu elements are unique and |
|
508 | // add to menu element list |
|
509 | 0 | if (appendMenuElements != null) |
510 | { |
|
511 | 0 | Iterator elementsIter = appendMenuElements.iterator(); |
512 | 0 | while (elementsIter.hasNext()) |
513 | { |
|
514 | 0 | appendMenuElement((MenuElementImpl)elementsIter.next(), menuElements); |
515 | } |
|
516 | } |
|
517 | 0 | } |
518 | ||
519 | /** |
|
520 | * removeMenuElements - remove from ordered list of unique menu |
|
521 | * option/menu elements |
|
522 | * |
|
523 | * @param removeMenuElements option/menu element list to remove |
|
524 | * @param menuElements option/menu element list |
|
525 | */ |
|
526 | private void removeMenuElements(List removeMenuElements, List menuElements) |
|
527 | { |
|
528 | // remove equivalent menu elements from menu |
|
529 | // element list |
|
530 | 0 | if (removeMenuElements != null) |
531 | { |
|
532 | 0 | menuElements.removeAll(removeMenuElements); |
533 | } |
|
534 | 0 | } |
535 | ||
536 | /** |
|
537 | * constructMenuElements - construct ordered list of menu elements in |
|
538 | * context/site view using specified element |
|
539 | * selection parameters; also sets up the |
|
540 | * elementRelative flag while constructing the |
|
541 | * menu elements |
|
542 | * |
|
543 | * @param context request context |
|
544 | * @param view context site view |
|
545 | * @param options option paths specification |
|
546 | * @param overrideElementProxies override menu element node proxies |
|
547 | * @param depth inclusion depth |
|
548 | * @param paths paths elements flag |
|
549 | * @param regexp regexp flag |
|
550 | * @param locatorName profile locator name |
|
551 | * @param order ordering patterns list |
|
552 | */ |
|
553 | private List constructMenuElements(PortalSiteRequestContextImpl context, SiteView view, String options, List overrideElementProxies, int depth, boolean paths, class="keyword">boolean regexp, String locatorName, String order) |
|
554 | { |
|
555 | 0 | if (options != null) |
556 | { |
|
557 | // use override element proxies if specified; otherwise |
|
558 | // compute proxy list using specified menu options |
|
559 | 0 | List elementProxies = overrideElementProxies; |
560 | 0 | if (elementProxies == null) |
561 | { |
|
562 | // split multiple comma separated option paths from specified options |
|
563 | 0 | String [] optionPaths = options.split(","); |
564 | ||
565 | // use regexp processing if specified or simple |
|
566 | // path evaluation to retrieve list of proxies from |
|
567 | // the site view for the specified options |
|
568 | 0 | for (int i = 0; (i < optionPaths.length); i++) |
569 | { |
|
570 | 0 | String optionPath = optionPaths[i].trim(); |
571 | 0 | if (optionPath.length() > 0) |
572 | { |
|
573 | // get proxies/proxy for path |
|
574 | 0 | if (regexp) |
575 | { |
|
576 | // get list of visible proxies for path from view and append |
|
577 | // to list if unique and pass profile locator name filter |
|
578 | 0 | List pathProxies = null; |
579 | try |
|
580 | { |
|
581 | 0 | pathProxies = view.getNodeProxies(optionPath, context.getPage(), true, class="keyword">true); |
582 | } |
|
583 | 0 | catch (NodeNotFoundException nnfe) |
584 | { |
|
585 | } |
|
586 | 0 | catch (SecurityException se) |
587 | { |
|
588 | 0 | } |
589 | 0 | if (pathProxies != null) |
590 | { |
|
591 | 0 | Iterator pathProxiesIter = pathProxies.iterator(); |
592 | 0 | while (pathProxiesIter.hasNext()) |
593 | { |
|
594 | 0 | Node pathProxy = (Node)pathProxiesIter.next(); |
595 | 0 | if ((locatorName == null) || locatorName.equals(MenuOptionsDefinition.ANY_PROFILE_LOCATOR) || |
596 | locatorName.equals(view.getProfileLocatorName(pathProxy))) |
|
597 | { |
|
598 | 0 | if (elementProxies == null) |
599 | { |
|
600 | 0 | elementProxies = new ArrayList(); |
601 | } |
|
602 | 0 | appendMenuElementProxies(pathProxy, elementProxies); |
603 | } |
|
604 | 0 | } |
605 | } |
|
606 | 0 | } |
607 | else |
|
608 | { |
|
609 | // get visible proxy for path from view and append to |
|
610 | // list if unique and pass profile locator name filter |
|
611 | 0 | Node pathProxy = null; |
612 | try |
|
613 | { |
|
614 | 0 | pathProxy = view.getNodeProxy(optionPath, context.getPage(), true, class="keyword">true); |
615 | } |
|
616 | 0 | catch (NodeNotFoundException nnfe) |
617 | { |
|
618 | } |
|
619 | 0 | catch (SecurityException se) |
620 | { |
|
621 | 0 | } |
622 | 0 | if ((pathProxy != null) && |
623 | ((locatorName == null) || locatorName.equals(MenuOptionsDefinition.ANY_PROFILE_LOCATOR) || |
|
624 | locatorName.equals(view.getProfileLocatorName(pathProxy)))) |
|
625 | { |
|
626 | 0 | if (elementProxies == null) |
627 | { |
|
628 | 0 | elementProxies = new ArrayList(); |
629 | } |
|
630 | 0 | appendMenuElementProxies(pathProxy, elementProxies); |
631 | } |
|
632 | } |
|
633 | ||
634 | // set relative element flag if path is relative |
|
635 | 0 | elementRelative = (elementRelative || !optionPath.startsWith(Folder.PATH_SEPARATOR)); |
636 | } |
|
637 | } |
|
638 | ||
639 | // return if no proxies available |
|
640 | 0 | if (elementProxies == null) |
641 | { |
|
642 | 0 | return null; |
643 | } |
|
644 | } |
|
645 | ||
646 | // sort elements proxies using url and/or names if order |
|
647 | // specified and more than one element proxy in list |
|
648 | 0 | if ((order != null) && (elementProxies.size() > 1)) |
649 | { |
|
650 | // create ordered element proxies |
|
651 | 0 | List orderedElementProxies = new ArrayList(elementProxies.size()); |
652 | ||
653 | // split multiple comma separated elements orderings |
|
654 | // after converted to regexp pattern |
|
655 | 0 | String [] orderings = orderRegexpPattern(order).split(","); |
656 | ||
657 | // copy ordered proxies per ordering |
|
658 | 0 | for (int i=0; ((i < orderings.length) && (elementProxies.size() > 1)); i++) |
659 | { |
|
660 | 0 | String ordering = orderings[i].trim(); |
661 | 0 | if (ordering.length() > 0) |
662 | { |
|
663 | // get ordering pattern and matcher |
|
664 | 0 | Pattern pattern = Pattern.compile(ordering); |
665 | 0 | Matcher matcher = null; |
666 | ||
667 | // use regular expression to match urls or names of |
|
668 | // element proxies; matched proxies are removed and |
|
669 | // placed in the ordered elements proxies list |
|
670 | 0 | Iterator elementProxiesIter = elementProxies.iterator(); |
671 | 0 | while (elementProxiesIter.hasNext()) |
672 | { |
|
673 | 0 | Node elementProxy = (Node)elementProxiesIter.next(); |
674 | ||
675 | // get url or name to test ordering match against |
|
676 | 0 | String test = null; |
677 | 0 | if (ordering.charAt(0) == Folder.PATH_SEPARATOR_CHAR) |
678 | { |
|
679 | 0 | test = elementProxy.getUrl(); |
680 | } |
|
681 | else |
|
682 | { |
|
683 | 0 | test = elementProxy.getName(); |
684 | } |
|
685 | ||
686 | // construct or reset ordering matcher |
|
687 | 0 | if (matcher == null) |
688 | { |
|
689 | 0 | matcher = pattern.matcher(test); |
690 | } |
|
691 | else |
|
692 | { |
|
693 | 0 | matcher.reset(test); |
694 | } |
|
695 | ||
696 | // move proxy to ordered list if matched |
|
697 | 0 | if (matcher.matches()) |
698 | { |
|
699 | 0 | orderedElementProxies.add(elementProxy); |
700 | 0 | elementProxiesIter.remove(); |
701 | } |
|
702 | 0 | } |
703 | } |
|
704 | } |
|
705 | ||
706 | // copy remaining unordered proxies |
|
707 | 0 | orderedElementProxies.addAll(elementProxies); |
708 | ||
709 | // replace element proxies with ordered list |
|
710 | 0 | elementProxies = orderedElementProxies; |
711 | } |
|
712 | ||
713 | // expand paths if single page or folder element proxy |
|
714 | // has been specified in elements with no depth expansion |
|
715 | 0 | if (paths && (depth == 0) && (elementProxies.size() == 1) && |
716 | ((elementProxies.get(0) instanceof Folder) || (elementProxies.get(0) instanceof Page))) |
|
717 | { |
|
718 | 0 | Node parentNode = ((Node)elementProxies.get(0)).getParent(); |
719 | 0 | while (parentNode != null) |
720 | { |
|
721 | 0 | elementProxies.add(0, parentNode); |
722 | 0 | parentNode = parentNode.getParent(); |
723 | } |
|
724 | } |
|
725 | ||
726 | // convert elements proxies into menu elements |
|
727 | 0 | DefaultMenuOptionsDefinition defaultMenuOptionsDefinition = null; |
728 | 0 | ListIterator elementProxiesIter = elementProxies.listIterator(); |
729 | 0 | while (elementProxiesIter.hasNext()) |
730 | { |
|
731 | 0 | Node elementProxy = (Node)elementProxiesIter.next(); |
732 | 0 | MenuElement menuElement = null; |
733 | ||
734 | // convert folders into nested menus if depth specified |
|
735 | // with no paths expansion, (negative depth values are |
|
736 | // interpreted as complete menu expansion) |
|
737 | 0 | if ((elementProxy instanceof Folder) && ((depth < 0) || (depth > 1)) && !paths) |
738 | { |
|
739 | // construct menu definition and associated menu |
|
740 | 0 | MenuDefinition nestedMenuDefinition = new DefaultMenuDefinition(elementProxy.getUrl(), depth - 1, locatorName); |
741 | 0 | menuElement = new MenuImpl(this, nestedMenuDefinition, context, null); |
742 | 0 | } |
743 | else |
|
744 | { |
|
745 | // construct shared default menu option definition and menu option |
|
746 | 0 | if (defaultMenuOptionsDefinition == null) |
747 | { |
|
748 | 0 | defaultMenuOptionsDefinition = new DefaultMenuOptionsDefinition(options, depth, paths, regexp, locatorName, order); |
749 | } |
|
750 | 0 | menuElement = new MenuOptionImpl(this, elementProxy, defaultMenuOptionsDefinition); |
751 | } |
|
752 | ||
753 | // replace element proxy with menu element |
|
754 | 0 | elementProxiesIter.set(menuElement); |
755 | 0 | } |
756 | 0 | List menuElements = elementProxies; |
757 | ||
758 | // return list of menu elements constructed from element proxies |
|
759 | 0 | return menuElements; |
760 | } |
|
761 | ||
762 | // no options specified |
|
763 | 0 | return null; |
764 | } |
|
765 | ||
766 | /** |
|
767 | * appendMenuElementProxies - append to ordered list of unique menu |
|
768 | * element proxies |
|
769 | * |
|
770 | * @param pathProxy menu element page, folder, or link proxy at path |
|
771 | * @param elementProxies element proxies list |
|
772 | */ |
|
773 | private void appendMenuElementProxies(Node pathProxy, List elementProxies) |
|
774 | { |
|
775 | // make sure new proxy is unique and add |
|
776 | // to element proxies list |
|
777 | 0 | if (!elementProxies.contains(pathProxy)) |
778 | { |
|
779 | 0 | elementProxies.add(pathProxy); |
780 | } |
|
781 | 0 | } |
782 | ||
783 | /** |
|
784 | * clone - clone this instance |
|
785 | * |
|
786 | * @return unparented deep copy |
|
787 | */ |
|
788 | public Object clone() throws CloneNotSupportedException |
|
789 | { |
|
790 | // clone this object |
|
791 | 0 | MenuImpl copy = (MenuImpl)super.clone(); |
792 | ||
793 | // clone and reparent copy elements |
|
794 | 0 | if (copy.elements != null) |
795 | { |
|
796 | 0 | Iterator elementsIter = copy.elements.iterator(); |
797 | 0 | copy.elements = new ArrayList(copy.elements.size()); |
798 | 0 | while (elementsIter.hasNext()) |
799 | { |
|
800 | 0 | MenuElementImpl elementCopy = (MenuElementImpl)((MenuElementImpl)elementsIter.next()).clone(); |
801 | 0 | elementCopy.setParentMenu(copy); |
802 | 0 | copy.elements.add(elementCopy); |
803 | 0 | } |
804 | } |
|
805 | 0 | return copy; |
806 | } |
|
807 | ||
808 | /** |
|
809 | * getElementType - get type of menu element |
|
810 | * |
|
811 | * @return MENU_ELEMENT_TYPE |
|
812 | */ |
|
813 | public String getElementType() |
|
814 | { |
|
815 | 0 | return MENU_ELEMENT_TYPE; |
816 | } |
|
817 | ||
818 | /** |
|
819 | * getName - get name of menu |
|
820 | * |
|
821 | * @return menu name |
|
822 | */ |
|
823 | public String getName() |
|
824 | { |
|
825 | 0 | return definition.getName(); |
826 | } |
|
827 | ||
828 | /** |
|
829 | * getTitle - get default title for menu element |
|
830 | * |
|
831 | * @return title text |
|
832 | */ |
|
833 | public String getTitle() |
|
834 | { |
|
835 | // return definition title |
|
836 | 0 | String title = definition.getTitle(); |
837 | 0 | if (title != null) |
838 | { |
|
839 | 0 | return title; |
840 | } |
|
841 | // return node or default title |
|
842 | 0 | return super.getTitle(); |
843 | } |
|
844 | ||
845 | /** |
|
846 | * getShortTitle - get default short title for menu element |
|
847 | * |
|
848 | * @return short title text |
|
849 | */ |
|
850 | public String getShortTitle() |
|
851 | { |
|
852 | // return definition short title |
|
853 | 0 | String title = definition.getShortTitle(); |
854 | 0 | if (title != null) |
855 | { |
|
856 | 0 | return title; |
857 | } |
|
858 | ||
859 | // return node or default short title |
|
860 | 0 | return super.getShortTitle(); |
861 | } |
|
862 | ||
863 | /** |
|
864 | * getTitle - get locale specific title for menu element |
|
865 | * from metadata |
|
866 | * |
|
867 | * @param locale preferred locale |
|
868 | * @return title text |
|
869 | */ |
|
870 | public String getTitle(Locale locale) |
|
871 | { |
|
872 | // return definition short title for preferred locale |
|
873 | 0 | String title = definition.getTitle(locale); |
874 | 0 | if (title != null) |
875 | { |
|
876 | 0 | return title; |
877 | } |
|
878 | ||
879 | // return node or default title for preferred locale |
|
880 | 0 | return super.getTitle(locale); |
881 | } |
|
882 | ||
883 | /** |
|
884 | * getShortTitle - get locale specific short title for menu |
|
885 | * element from metadata |
|
886 | * |
|
887 | * @param locale preferred locale |
|
888 | * @return short title text |
|
889 | */ |
|
890 | public String getShortTitle(Locale locale) |
|
891 | { |
|
892 | // return definition short title for preferred locale |
|
893 | 0 | String title = definition.getShortTitle(locale); |
894 | 0 | if (title != null) |
895 | { |
|
896 | 0 | return title; |
897 | } |
|
898 | ||
899 | // return node or default short title for preferred locale |
|
900 | 0 | return super.getShortTitle(locale); |
901 | } |
|
902 | ||
903 | /** |
|
904 | * getMetadata - get generic metadata for menu element |
|
905 | * |
|
906 | * @return metadata |
|
907 | */ |
|
908 | public GenericMetadata getMetadata() |
|
909 | { |
|
910 | // return definition metadata |
|
911 | 0 | GenericMetadata metadata = definition.getMetadata(); |
912 | 0 | if ((metadata != null) && (metadata.getFields() != class="keyword">null) && !metadata.getFields().isEmpty()) |
913 | { |
|
914 | 0 | return metadata; |
915 | } |
|
916 | ||
917 | // return node metadata |
|
918 | 0 | return super.getMetadata(); |
919 | } |
|
920 | ||
921 | /** |
|
922 | * getSkin - get skin name for menu element |
|
923 | * |
|
924 | * @return skin name |
|
925 | */ |
|
926 | public String getSkin() |
|
927 | { |
|
928 | // get skin from definition or inherit from parent menu |
|
929 | 0 | String skin = definition.getSkin(); |
930 | 0 | if (skin == null) |
931 | { |
|
932 | 0 | skin = super.getSkin(); |
933 | } |
|
934 | 0 | return skin; |
935 | } |
|
936 | ||
937 | /** |
|
938 | * getUrl - get url of top level folder that defined |
|
939 | * menu options; only available for menus |
|
940 | * defined without multiple options, nested |
|
941 | * menus, or separators |
|
942 | * |
|
943 | * @return folder url |
|
944 | */ |
|
945 | public String getUrl() |
|
946 | { |
|
947 | // return url of node associated with menu |
|
948 | // option if defined |
|
949 | 0 | if (getNode() != null) |
950 | { |
|
951 | 0 | return getNode().getUrl(); |
952 | } |
|
953 | 0 | return null; |
954 | } |
|
955 | ||
956 | /** |
|
957 | * isHidden - get hidden state of folder that defined |
|
958 | * menu options; only available for menus |
|
959 | * defined without multiple options, nested |
|
960 | * menus, or separators |
|
961 | * |
|
962 | * @return hidden state |
|
963 | */ |
|
964 | public boolean isHidden() |
|
965 | { |
|
966 | // return hidden state of node associated with |
|
967 | // menu option if defined |
|
968 | 0 | if (getNode() != null) |
969 | { |
|
970 | 0 | return getNode().isHidden(); |
971 | } |
|
972 | 0 | return false; |
973 | } |
|
974 | ||
975 | /** |
|
976 | * isSelected - return true if an option or nested |
|
977 | * menu within this menu are selected by |
|
978 | * the specified request context |
|
979 | * |
|
980 | * @param context request context |
|
981 | * @return selected state |
|
982 | */ |
|
983 | public boolean isSelected(PortalSiteRequestContext context) |
|
984 | { |
|
985 | // menu is selected if a selected element exists |
|
986 | 0 | return (getSelectedElement(context) != null); |
987 | } |
|
988 | ||
989 | /** |
|
990 | * getElements - get ordered list of menu elements that |
|
991 | * are members of this menu; possibly contains |
|
992 | * options, nested menus, or separators |
|
993 | * |
|
994 | * @return menu elements list |
|
995 | */ |
|
996 | public List getElements() |
|
997 | { |
|
998 | 0 | return elements; |
999 | } |
|
1000 | ||
1001 | /** |
|
1002 | * isEmpty - get empty state of list of menu elements |
|
1003 | * |
|
1004 | * @return menu elements list empty state |
|
1005 | */ |
|
1006 | public boolean isEmpty() |
|
1007 | { |
|
1008 | 0 | return ((elements == null) || elements.isEmpty()); |
1009 | } |
|
1010 | ||
1011 | /** |
|
1012 | * isElementRelative - get flag that indicates whether any relative paths |
|
1013 | * dependent on the current page in context were |
|
1014 | * referenced while constructing menu elements |
|
1015 | * |
|
1016 | * @return relative element status |
|
1017 | */ |
|
1018 | public boolean isElementRelative() |
|
1019 | { |
|
1020 | 0 | return elementRelative; |
1021 | } |
|
1022 | ||
1023 | /** |
|
1024 | * getSelectedElement - return selected option or nested |
|
1025 | * menu within this menu selected by |
|
1026 | * the specified request context |
|
1027 | * |
|
1028 | * @return selected menu element |
|
1029 | */ |
|
1030 | public MenuElement getSelectedElement(PortalSiteRequestContext context) |
|
1031 | { |
|
1032 | // test nested menu and option menu |
|
1033 | // elements for selected status |
|
1034 | 0 | if (elements != null) |
1035 | { |
|
1036 | 0 | Iterator elementsIter = elements.iterator(); |
1037 | 0 | while (elementsIter.hasNext()) |
1038 | { |
|
1039 | 0 | MenuElement element = (MenuElement)elementsIter.next(); |
1040 | ||
1041 | // test element selected |
|
1042 | 0 | boolean selected = false; |
1043 | 0 | if (element instanceof MenuOption) |
1044 | { |
|
1045 | 0 | selected = ((MenuOption)element).isSelected(context); |
1046 | } |
|
1047 | 0 | else if (element instanceof Menu) |
1048 | { |
|
1049 | 0 | selected = ((Menu)element).isSelected(context); |
1050 | } |
|
1051 | ||
1052 | // return selected element |
|
1053 | 0 | if (selected) |
1054 | { |
|
1055 | 0 | return element; |
1056 | } |
|
1057 | 0 | } |
1058 | } |
|
1059 | 0 | return null; |
1060 | } |
|
1061 | ||
1062 | /** |
|
1063 | * orderRegexpPattern - tests for and converts simple order wildcard |
|
1064 | * and character class regular exressions to |
|
1065 | * perl5/standard java pattern syntax |
|
1066 | * |
|
1067 | * @param regexp - candidate order regular expression |
|
1068 | * @return - converted pattern |
|
1069 | */ |
|
1070 | private static String orderRegexpPattern(String regexp) |
|
1071 | { |
|
1072 | // convert expression to pattern |
|
1073 | 0 | StringBuffer pattern = null; |
1074 | 0 | for (int i = 0, limit = regexp.length(); (i < limit); i++) |
1075 | { |
|
1076 | 0 | char regexpChar = regexp.class="keyword">charAt(i); |
1077 | 0 | switch (regexpChar) |
1078 | { |
|
1079 | case '*': |
|
1080 | case '.': |
|
1081 | case '?': |
|
1082 | case '[': |
|
1083 | 0 | if (pattern == null) |
1084 | { |
|
1085 | 0 | pattern = new StringBuffer(regexp.length()*2); |
1086 | 0 | pattern.append(regexp.substring(0, i)); |
1087 | } |
|
1088 | 0 | switch (regexpChar) |
1089 | { |
|
1090 | case '*': |
|
1091 | 0 | pattern.append("[^"+Folder.PATH_SEPARATOR+"]*"); |
1092 | 0 | break; |
1093 | case '.': |
|
1094 | 0 | pattern.append("\\."); |
1095 | 0 | break; |
1096 | case '?': |
|
1097 | 0 | pattern.append("[^"+Folder.PATH_SEPARATOR+"]"); |
1098 | 0 | break; |
1099 | case '[': |
|
1100 | 0 | pattern.append('['); |
1101 | break; |
|
1102 | } |
|
1103 | 0 | break; |
1104 | default: |
|
1105 | 0 | if (pattern != null) |
1106 | { |
|
1107 | 0 | pattern.append(regexpChar); |
1108 | } |
|
1109 | break; |
|
1110 | } |
|
1111 | } |
|
1112 | ||
1113 | // return converted pattern |
|
1114 | 0 | if (pattern != null) |
1115 | 0 | return pattern.toString(); |
1116 | 0 | return regexp; |
1117 | } |
|
1118 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |