Coverage report

  %line %branch
org.apache.jetspeed.portalsite.impl.MenuImpl
0% 
0% 

 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.