You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@empire-db.apache.org by do...@apache.org on 2026/05/10 18:41:22 UTC

(empire-db) branch master updated: EMPIREDB-490 Improve MenuItemTag, MenuListTag to allow customization overrides

This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/empire-db.git


The following commit(s) were added to refs/heads/master by this push:
     new 6ba6fc01 EMPIREDB-490 Improve MenuItemTag, MenuListTag to allow customization overrides
6ba6fc01 is described below

commit 6ba6fc01ad9a09b899699f58fc5610b601c3d7ec
Author: Rainer Döbele <do...@apache.org>
AuthorDate: Sun May 10 20:41:19 2026 +0200

    EMPIREDB-490
    Improve MenuItemTag, MenuListTag to allow customization overrides
---
 .../empire/jakarta/components/MenuItemTag.java     | 159 +++++++++++----
 .../empire/jakarta/components/MenuListTag.java     | 223 ++++++++-------------
 .../apache/empire/jsf2/components/MenuItemTag.java | 159 +++++++++++----
 .../apache/empire/jsf2/components/MenuListTag.java | 223 ++++++++-------------
 4 files changed, 426 insertions(+), 338 deletions(-)

diff --git a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/MenuItemTag.java b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/MenuItemTag.java
index 1d0bb5b0..032217c2 100644
--- a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/MenuItemTag.java
+++ b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/MenuItemTag.java
@@ -23,6 +23,7 @@ import java.io.IOException;
 import org.apache.empire.commons.ObjectUtils;
 import org.apache.empire.commons.StringUtils;
 import org.apache.empire.jakarta.controls.InputControl;
+import org.apache.empire.jakarta.pages.PageDefinition;
 import org.apache.empire.jakarta.utils.TagEncodingHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -39,6 +40,9 @@ public class MenuItemTag extends LinkTag
     
     protected MenuListTag parentMenu;
     protected String menuId;
+    
+    private transient Boolean cachedIsRendered;
+    private transient Boolean cachedIsExpanded;
 
     public MenuItemTag()
     {
@@ -92,17 +96,59 @@ public class MenuItemTag extends LinkTag
         super.setId(id);
     }
     
+    @Override
+    public boolean isRendered()
+    {
+        // call base for default
+        if (!super.isRendered())
+            return false;
+        // detect if not already detected
+        if (cachedIsRendered== null)
+            cachedIsRendered = isRenderItem();
+        // render
+        return cachedIsRendered;
+    }
+    
+    public final String getMenuItemId()
+    {
+        if (menuId==null)
+            menuId = helper.getTagAttributeString("menuId");
+        return menuId;
+    }
+    
+    public final MenuListTag getParentMenu()
+    {
+        if (parentMenu==null)
+            parentMenu = findParentMenu();
+        return parentMenu;
+    }
+    
+    public final Object getAttribute(String attributeName)
+    {
+        return helper.getTagAttributeValue(attributeName);
+    }
+    
+    public final PageDefinition getPageDefinition()
+    {
+        // check page
+        Object pageDefinition = helper.getTagAttributeValue("page");
+        if (pageDefinition instanceof PageDefinition)
+            return (PageDefinition)pageDefinition;
+        else if (pageDefinition!=null)
+            log.warn("MenuItem attribute \"page\" is not a PageDefinition but a {}", pageDefinition.getClass().getName());
+        // not provided
+        return null;
+    }
+    
     @Override
     public void encodeBegin(FacesContext context)
         throws IOException
     {
         // Detect Parent Menu
-        parentMenu = findParentMenu();
+        if (parentMenu==null)
+            getParentMenu();
         if (menuId==null)
-            menuId = helper.getTagAttributeString("menuId");         
-        
-        if(!isRendered())
-            return;
+            getMenuItemId();         
         
         // render components
         ResponseWriter writer = context.getResponseWriter();
@@ -141,7 +187,7 @@ public class MenuItemTag extends LinkTag
     public void encodeChildren(FacesContext context)
         throws IOException
     {
-        if (isExpanded())
+        if (isItemExpanded())
         {
             UIComponent c = getChildren().get(0);
             if (c instanceof HtmlOutcomeTargetLink)
@@ -164,7 +210,7 @@ public class MenuItemTag extends LinkTag
         if(!isRendered())
             return;
         // call base
-        if (isExpanded())
+        if (isItemExpanded())
         {
             super.encodeEnd(context);
         }
@@ -195,32 +241,72 @@ public class MenuItemTag extends LinkTag
         return null;
     }
     
-    protected boolean isCurrent()
+    public boolean isCurrent()
     {
-        if (menuId==null || parentMenu==null || parentMenu.getCurrentItemId()==null)
+        if (getMenuItemId()==null || getParentMenu()==null || parentMenu.getCurrentItemId()==null)
             return false;
         // All present
         return menuId.equals(parentMenu.getCurrentItemId());
     }
     
-    protected boolean isParent()
+    public boolean isParent()
     {
-        if (menuId==null || parentMenu==null || parentMenu.getCurrentItemId()==null)
+        if (getMenuItemId()==null || getParentMenu()==null || parentMenu.getCurrentItemId()==null)
             return false;
         // All present
         String  currentId = parentMenu.getCurrentItemId();
         return (currentId.length()>menuId.length() && currentId.startsWith(menuId));
     }
 
-    protected boolean isDisabled()
+    public boolean isItemDisabled()
     {
         Object value = helper.getTagAttributeValue("disabled");
         if (value!=null)
             return ObjectUtils.getBoolean(value);
         return false;
     }
+    
+    public final boolean isItemExpanded()
+    {
+        if (cachedIsExpanded==null)
+            cachedIsExpanded=detectItemExpanded();
+        return cachedIsExpanded;
+    }
+    
+    /**
+     * Returns whether or not the MenuItem should be rendered
+     * Override this to implement custom logic
+     * @return true if the menu item should be rendered or false otherwise
+     */
+    protected boolean isRenderItem()
+    {
+        /*
+         * Example implementation for derived classes
+         * 
+        // check page
+        Object pageDefinition = helper.getTagAttributeValue("page");
+        if (pageDefinition instanceof PageDefinition)
+        {   // check whether to render the item
+            FacesContext fc = FacesContext.getCurrentInstance();
+            UIViewRoot vr = (fc!=null ? fc.getViewRoot() : null);
+            Map<String, Object> vm = (vr!=null ? vr.getViewMap(false) : null);
+            Page page = (Page) (vm!=null ?  vm.get("page") : null);
+            if (page!=null && !page.isRenderMenuItem(this))
+                return false;
+                
+        }
+         */
+        // check currentOnly
+        Object currentOnly = helper.getTagAttributeValue("currentOnly");
+        if (currentOnly!=null && ObjectUtils.getBoolean(currentOnly))
+        {   // Check current and parent
+            return isCurrent() || isParent();
+        }
+        // yes, render
+        return true;
+    }
 
-    protected boolean isExpanded()
+    protected boolean detectItemExpanded()
     {
         Object value = helper.getTagAttributeValue("expanded");
         boolean auto = false;
@@ -234,30 +320,13 @@ public class MenuItemTag extends LinkTag
                 return true;
         }
         // Check parent
-        if (menuId==null || parentMenu==null || parentMenu.getCurrentItemId()==null)
+        if (getMenuItemId()==null || getParentMenu()==null || parentMenu.getCurrentItemId()==null)
             return auto;
         // All present
         String currentId = parentMenu.getCurrentItemId();
         return currentId.startsWith(menuId+".");
     }
     
-    @Override
-    public boolean isRendered()
-    {
-        Object value = helper.getTagAttributeValue("currentOnly");
-        boolean currentOnly = false;
-        if (value!=null)
-            currentOnly = ObjectUtils.getBoolean(value);
-        
-        // Check parent
-        if (currentOnly && menuId!=null && parentMenu!=null && parentMenu.getCurrentItemId()!=null)
-        {    
-            return isCurrent() || isParent();
-        }
-        
-        return super.isRendered();
-    }
-    
     protected String getStyleClass()
     {
         String styleClass = helper.getTagAttributeString(InputControl.CSS_STYLE_CLASS);
@@ -272,15 +341,15 @@ public class MenuItemTag extends LinkTag
             else if (isParent())
                 styleClass = appendStyleClass(styleClass, parentMenu.getParentItemClass());
             // expanded
-            if (isExpanded())
+            if (isItemExpanded())
                 styleClass = appendStyleClass(styleClass, parentMenu.getItemExpandedClass());            
             // Disabled / enabled
-            if (isDisabled())
+            if (isItemDisabled())
                 styleClass = appendStyleClass(styleClass, parentMenu.getItemDisabledClass());
         }
         else
         {   // disabled
-            if (isDisabled())
+            if (isItemDisabled())
                 styleClass = appendStyleClass(styleClass, "disabled");
         }
         // both supplied
@@ -299,7 +368,27 @@ public class MenuItemTag extends LinkTag
     {
         return false;
     }
-
+    
+    /**
+     * Returns the menu item label
+     * Override this to e.g. provide the label from the PageDefinition
+     * @return the menu item label
+     */
+    @Override
+    protected Object getLinkValue(boolean hasColumn)
+    {
+        Object label = super.getLinkValue(hasColumn);
+        /*
+         * Example implementation for derived classes
+         * 
+        if (label==null && getFacet("label")==null)
+        {   // Set title from PageDefinition
+            PageDefinition pageDef = getPageDefinition();
+            label = helper.getTextResolver(FacesContext.getCurrentInstance()).resolveKey("pageTitle."+pageDef.getPageBeanName());
+        }
+         */
+        return label; 
+    }
     
     /* 
      * Supports a "label" facet" e.g.
diff --git a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/MenuListTag.java b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/MenuListTag.java
index 51257ae2..085c6664 100644
--- a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/MenuListTag.java
+++ b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/MenuListTag.java
@@ -50,6 +50,7 @@ public class MenuListTag extends UIOutput implements TagEncodingHolder
         defaultItemClass;
     }
     
+    protected MenuListTag parentMenu = null;
     protected String currentId = null; 
     protected String currentClass = null; 
     protected String parentClass = null;
@@ -59,8 +60,8 @@ public class MenuListTag extends UIOutput implements TagEncodingHolder
     protected String defaultItemClass = null; // e.g. "level{}"
     protected int level = 0;
     
-    private MenuListTag parentMenu = null; 
-
+    private transient Boolean cachedIsRendered;
+    
     @Override
     public String getFamily()
     {
@@ -72,6 +73,19 @@ public class MenuListTag extends UIOutput implements TagEncodingHolder
     {
         return helper;
     }
+    
+    @Override
+    public boolean isRendered()
+    {
+        // call base for default
+        if (!super.isRendered())
+            return false;
+        // detect if not already detected
+        if (cachedIsRendered== null)
+            cachedIsRendered = isRenderList();
+        // render
+        return cachedIsRendered;
+    }
         
     @Override
     public void encodeBegin(FacesContext context)
@@ -80,7 +94,7 @@ public class MenuListTag extends UIOutput implements TagEncodingHolder
         // call base
         super.encodeBegin(context);
         
-        initMenuAttributes(context);
+        initMenuAttributes();
 
         // render components
         ResponseWriter writer = context.getResponseWriter();
@@ -119,51 +133,16 @@ public class MenuListTag extends UIOutput implements TagEncodingHolder
         writer.endElement("ul");
     }
     
-    protected void initMenuAttributes(FacesContext context)
-    {        
-        currentId        = helper.getTagAttributeString(MenuProperty.currentId.name()); 
-        currentClass     = helper.getTagAttributeString(MenuProperty.currentClass.name()); 
-        parentClass      = helper.getTagAttributeString(MenuProperty.parentClass.name());
-        disabledClass    = helper.getTagAttributeString(MenuProperty.disabledClass.name()); 
-        expandedClass    = helper.getTagAttributeString(MenuProperty.expandedClass.name());
-        itemWrapTag      = helper.getTagAttributeString(MenuProperty.itemWrapTag.name());
-        defaultItemClass = helper.getTagAttributeString(MenuProperty.defaultItemClass.name());
-
-        // find parent
+    public Object getAttribute(String attributeName)
+    {
+        return helper.getTagAttributeValue(attributeName);
+    }
+    
+    public final MenuListTag getParentMenu()
+    {
         if (parentMenu==null)
             parentMenu = findParentMenu();
-        if (parentMenu==null)
-        {   // the root menu
-            if (currentClass==null)
-                currentClass = "current";  
-            if (parentClass==null)
-                parentClass = "parent";
-            if (disabledClass==null)
-                disabledClass = "parent";
-            if (expandedClass==null)
-                expandedClass = "expanded";
-            // level
-            level = 0;
-        }
-        else
-        {   // copy from parent
-            if (currentId==null)
-                currentId = parentMenu.getCurrentItemId();
-            if (currentClass==null)
-                currentClass = parentMenu.getCurrentItemClass();  
-            if (parentClass==null)
-                parentClass = parentMenu.getParentItemClass();
-            if (disabledClass==null)
-                disabledClass = parentMenu.getItemDisabledClass();
-            if (expandedClass==null)
-                expandedClass = parentMenu.getItemExpandedClass();
-            if (itemWrapTag==null)
-                itemWrapTag = parentMenu.getItemWrapperTagName();
-            if (defaultItemClass==null)
-                defaultItemClass = parentMenu.defaultItemClass;
-            // increase level
-            level = parentMenu.level + 1;
-        }
+        return parentMenu;
     }
     
     public String getCurrentItemId()
@@ -219,100 +198,76 @@ public class MenuListTag extends UIOutput implements TagEncodingHolder
         return defaultItemClass;
     }
 
-    /* 
-     * Getters and setter with getStateHelper()
-     * Removed with EMPIREDB-441 on 2024-10-12
-     * 
+    /*
+     * helpers
+     */
     
-    public String getCurrentItemId()
-    {
-        if (currentId==null)
-            currentId= StringUtils.toString(getStateHelper().get(MenuProperty.currentId));
-        return currentId;
-    }
-
-    public String getCurrentItemClass()
-    {
-        if (currentClass==null)
-            currentClass= StringUtils.toString(getStateHelper().get(MenuProperty.currentClass));
-        return currentClass;
-    }
-
-    public String getParentItemClass()
-    {
-        if (parentClass==null)
-            parentClass= StringUtils.toString(getStateHelper().get(MenuProperty.parentClass));
-        return parentClass;
-    }
-
-    public String getItemDisabledClass()
-    {
-        if (disabledClass==null)
-            disabledClass= StringUtils.toString(getStateHelper().get(MenuProperty.disabledClass));
-        return disabledClass;
-    }
-
-    public String getItemExpandedClass()
-    {
-        if (expandedClass==null)
-            expandedClass= StringUtils.toString(getStateHelper().get(MenuProperty.expandedClass));
-        return expandedClass;
-    }
-
-    public String getItemWrapperTagName()
+    /**
+     * Returns whether or not the MenuList should be rendered
+     * Override this to implement custom logic
+     * @return true if the menu item should be rendered or false otherwise
+     */
+    protected boolean isRenderList()
     {
-        if (itemWrapTag==null)
-            itemWrapTag= StringUtils.toString(getStateHelper().get(MenuProperty.itemWrapTag));
-        return itemWrapTag;
+        /*
+         * Example implementation for derived classes
+         * 
+        // check whether to render the menu list
+        FacesContext fc = FacesContext.getCurrentInstance();
+        UIViewRoot vr = (fc!=null ? fc.getViewRoot() : null);
+        Map<String, Object> vm = (vr!=null ? vr.getViewMap(false) : null);
+        Page page = (Page) (vm!=null ?  vm.get("page") : null);
+        if (page!=null && !page.isRenderMenuList(this))
+            return false;
+         */    
+        // yes, render
+        return true;
     }
     
-    public void setCurrentId(String currentId)
-    {
-        this.currentId = currentId;
-        // save
-        getStateHelper().put(MenuProperty.currentId, currentId);
-    }
-
-    public void setCurrentClass(String currentClass)
-    {
-        this.currentClass = currentClass;
-        // save
-        getStateHelper().put(MenuProperty.currentClass, currentClass);
-    }
-
-    public void setDisabledClass(String disabledClass)
-    {
-        this.disabledClass = disabledClass;
-        // save
-        getStateHelper().put(MenuProperty.disabledClass, disabledClass);
-    }
-
-    public void setParentClass(String parentClass)
-    {
-        this.parentClass = parentClass;
-        // save
-        getStateHelper().put(MenuProperty.parentClass, parentClass);
-    }
-
-    public void setExpandedClass(String expandedClass)
-    {
-        this.expandedClass = expandedClass;
-        // save
-        getStateHelper().put(MenuProperty.expandedClass, expandedClass);
-    }
+    protected void initMenuAttributes()
+    {        
+        currentId        = helper.getTagAttributeString(MenuProperty.currentId.name()); 
+        currentClass     = helper.getTagAttributeString(MenuProperty.currentClass.name()); 
+        parentClass      = helper.getTagAttributeString(MenuProperty.parentClass.name());
+        disabledClass    = helper.getTagAttributeString(MenuProperty.disabledClass.name()); 
+        expandedClass    = helper.getTagAttributeString(MenuProperty.expandedClass.name());
+        itemWrapTag      = helper.getTagAttributeString(MenuProperty.itemWrapTag.name());
+        defaultItemClass = helper.getTagAttributeString(MenuProperty.defaultItemClass.name());
 
-    public void setItemWrapTag(String itemWrapTag)
-    {
-        this.itemWrapTag = itemWrapTag;
-        // save
-        getStateHelper().put(MenuProperty.itemWrapTag, itemWrapTag);
+        // find parent
+        if (getParentMenu()==null)
+        {   // the root menu
+            if (currentClass==null)
+                currentClass = "current";  
+            if (parentClass==null)
+                parentClass = "parent";
+            if (disabledClass==null)
+                disabledClass = "parent";
+            if (expandedClass==null)
+                expandedClass = "expanded";
+            // level
+            level = 0;
+        }
+        else
+        {   // copy from parent
+            if (currentId==null)
+                currentId = parentMenu.getCurrentItemId();
+            if (currentClass==null)
+                currentClass = parentMenu.getCurrentItemClass();  
+            if (parentClass==null)
+                parentClass = parentMenu.getParentItemClass();
+            if (disabledClass==null)
+                disabledClass = parentMenu.getItemDisabledClass();
+            if (expandedClass==null)
+                expandedClass = parentMenu.getItemExpandedClass();
+            if (itemWrapTag==null)
+                itemWrapTag = parentMenu.getItemWrapperTagName();
+            if (defaultItemClass==null)
+                defaultItemClass = parentMenu.defaultItemClass;
+            // increase level
+            level = parentMenu.level + 1;
+        }
     }
-    
-    */
-
-    /*
-     * helpers
-     */
 
     protected MenuListTag findParentMenu()
     {
diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/MenuItemTag.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/MenuItemTag.java
index c2f122d4..877dc8ca 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/MenuItemTag.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/MenuItemTag.java
@@ -28,6 +28,7 @@ import javax.faces.context.ResponseWriter;
 import org.apache.empire.commons.ObjectUtils;
 import org.apache.empire.commons.StringUtils;
 import org.apache.empire.jsf2.controls.InputControl;
+import org.apache.empire.jsf2.pages.PageDefinition;
 import org.apache.empire.jsf2.utils.TagEncodingHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -39,6 +40,9 @@ public class MenuItemTag extends LinkTag
     
     protected MenuListTag parentMenu;
     protected String menuId;
+    
+    private transient Boolean cachedIsRendered;
+    private transient Boolean cachedIsExpanded;
 
     public MenuItemTag()
     {
@@ -92,17 +96,59 @@ public class MenuItemTag extends LinkTag
         super.setId(id);
     }
     
+    @Override
+    public boolean isRendered()
+    {
+        // call base for default
+        if (!super.isRendered())
+            return false;
+        // detect if not already detected
+        if (cachedIsRendered== null)
+            cachedIsRendered = isRenderItem();
+        // render
+        return cachedIsRendered;
+    }
+    
+    public final String getMenuItemId()
+    {
+        if (menuId==null)
+            menuId = helper.getTagAttributeString("menuId");
+        return menuId;
+    }
+    
+    public final MenuListTag getParentMenu()
+    {
+        if (parentMenu==null)
+            parentMenu = findParentMenu();
+        return parentMenu;
+    }
+    
+    public final Object getAttribute(String attributeName)
+    {
+        return helper.getTagAttributeValue(attributeName);
+    }
+    
+    public final PageDefinition getPageDefinition()
+    {
+        // check page
+        Object pageDefinition = helper.getTagAttributeValue("page");
+        if (pageDefinition instanceof PageDefinition)
+            return (PageDefinition)pageDefinition;
+        else if (pageDefinition!=null)
+            log.warn("MenuItem attribute \"page\" is not a PageDefinition but a {}", pageDefinition.getClass().getName());
+        // not provided
+        return null;
+    }
+    
     @Override
     public void encodeBegin(FacesContext context)
         throws IOException
     {
         // Detect Parent Menu
-        parentMenu = findParentMenu();
+        if (parentMenu==null)
+            getParentMenu();
         if (menuId==null)
-            menuId = helper.getTagAttributeString("menuId");         
-        
-        if(!isRendered())
-            return;
+            getMenuItemId();         
         
         // render components
         ResponseWriter writer = context.getResponseWriter();
@@ -141,7 +187,7 @@ public class MenuItemTag extends LinkTag
     public void encodeChildren(FacesContext context)
         throws IOException
     {
-        if (isExpanded())
+        if (isItemExpanded())
         {
             UIComponent c = getChildren().get(0);
             if (c instanceof HtmlOutcomeTargetLink)
@@ -164,7 +210,7 @@ public class MenuItemTag extends LinkTag
         if(!isRendered())
             return;
         // call base
-        if (isExpanded())
+        if (isItemExpanded())
         {
             super.encodeEnd(context);
         }
@@ -195,32 +241,72 @@ public class MenuItemTag extends LinkTag
         return null;
     }
     
-    protected boolean isCurrent()
+    public boolean isCurrent()
     {
-        if (menuId==null || parentMenu==null || parentMenu.getCurrentItemId()==null)
+        if (getMenuItemId()==null || getParentMenu()==null || parentMenu.getCurrentItemId()==null)
             return false;
         // All present
         return menuId.equals(parentMenu.getCurrentItemId());
     }
     
-    protected boolean isParent()
+    public boolean isParent()
     {
-        if (menuId==null || parentMenu==null || parentMenu.getCurrentItemId()==null)
+        if (getMenuItemId()==null || getParentMenu()==null || parentMenu.getCurrentItemId()==null)
             return false;
         // All present
         String  currentId = parentMenu.getCurrentItemId();
         return (currentId.length()>menuId.length() && currentId.startsWith(menuId));
     }
 
-    protected boolean isDisabled()
+    public boolean isItemDisabled()
     {
         Object value = helper.getTagAttributeValue("disabled");
         if (value!=null)
             return ObjectUtils.getBoolean(value);
         return false;
     }
+    
+    public final boolean isItemExpanded()
+    {
+        if (cachedIsExpanded==null)
+            cachedIsExpanded=detectItemExpanded();
+        return cachedIsExpanded;
+    }
+    
+    /**
+     * Returns whether or not the MenuItem should be rendered
+     * Override this to implement custom logic
+     * @return true if the menu item should be rendered or false otherwise
+     */
+    protected boolean isRenderItem()
+    {
+        /*
+         * Example implementation for derived classes
+         * 
+        // check page
+        Object pageDefinition = helper.getTagAttributeValue("page");
+        if (pageDefinition instanceof PageDefinition)
+        {   // check whether to render the item
+            FacesContext fc = FacesContext.getCurrentInstance();
+            UIViewRoot vr = (fc!=null ? fc.getViewRoot() : null);
+            Map<String, Object> vm = (vr!=null ? vr.getViewMap(false) : null);
+            Page page = (Page) (vm!=null ?  vm.get("page") : null);
+            if (page!=null && !page.isRenderMenuItem(this))
+                return false;
+                
+        }
+         */
+        // check currentOnly
+        Object currentOnly = helper.getTagAttributeValue("currentOnly");
+        if (currentOnly!=null && ObjectUtils.getBoolean(currentOnly))
+        {   // Check current and parent
+            return isCurrent() || isParent();
+        }
+        // yes, render
+        return true;
+    }
 
-    protected boolean isExpanded()
+    protected boolean detectItemExpanded()
     {
         Object value = helper.getTagAttributeValue("expanded");
         boolean auto = false;
@@ -234,30 +320,13 @@ public class MenuItemTag extends LinkTag
                 return true;
         }
         // Check parent
-        if (menuId==null || parentMenu==null || parentMenu.getCurrentItemId()==null)
+        if (getMenuItemId()==null || getParentMenu()==null || parentMenu.getCurrentItemId()==null)
             return auto;
         // All present
         String currentId = parentMenu.getCurrentItemId();
         return currentId.startsWith(menuId+".");
     }
     
-    @Override
-    public boolean isRendered()
-    {
-        Object value = helper.getTagAttributeValue("currentOnly");
-        boolean currentOnly = false;
-        if (value!=null)
-            currentOnly = ObjectUtils.getBoolean(value);
-        
-        // Check parent
-        if (currentOnly && menuId!=null && parentMenu!=null && parentMenu.getCurrentItemId()!=null)
-        {    
-            return isCurrent() || isParent();
-        }
-        
-        return super.isRendered();
-    }
-    
     protected String getStyleClass()
     {
         String styleClass = helper.getTagAttributeString(InputControl.CSS_STYLE_CLASS);
@@ -272,15 +341,15 @@ public class MenuItemTag extends LinkTag
             else if (isParent())
                 styleClass = appendStyleClass(styleClass, parentMenu.getParentItemClass());
             // expanded
-            if (isExpanded())
+            if (isItemExpanded())
                 styleClass = appendStyleClass(styleClass, parentMenu.getItemExpandedClass());            
             // Disabled / enabled
-            if (isDisabled())
+            if (isItemDisabled())
                 styleClass = appendStyleClass(styleClass, parentMenu.getItemDisabledClass());
         }
         else
         {   // disabled
-            if (isDisabled())
+            if (isItemDisabled())
                 styleClass = appendStyleClass(styleClass, "disabled");
         }
         // both supplied
@@ -299,7 +368,27 @@ public class MenuItemTag extends LinkTag
     {
         return false;
     }
-
+    
+    /**
+     * Returns the menu item label
+     * Override this to e.g. provide the label from the PageDefinition
+     * @return the menu item label
+     */
+    @Override
+    protected Object getLinkValue(boolean hasColumn)
+    {
+        Object label = super.getLinkValue(hasColumn);
+        /*
+         * Example implementation for derived classes
+         * 
+        if (label==null && getFacet("label")==null)
+        {   // Set title from PageDefinition
+            PageDefinition pageDef = getPageDefinition();
+            label = helper.getTextResolver(FacesContext.getCurrentInstance()).resolveKey("pageTitle."+pageDef.getPageBeanName());
+        }
+         */
+        return label; 
+    }
     
     /* 
      * Supports a "label" facet" e.g.
diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/MenuListTag.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/MenuListTag.java
index c4cc2393..de5e3201 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/MenuListTag.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/MenuListTag.java
@@ -50,6 +50,7 @@ public class MenuListTag extends UIOutput implements TagEncodingHolder
         defaultItemClass;
     }
     
+    protected MenuListTag parentMenu = null;
     protected String currentId = null; 
     protected String currentClass = null; 
     protected String parentClass = null;
@@ -59,8 +60,8 @@ public class MenuListTag extends UIOutput implements TagEncodingHolder
     protected String defaultItemClass = null; // e.g. "level{}"
     protected int level = 0;
     
-    private MenuListTag parentMenu = null; 
-
+    private transient Boolean cachedIsRendered;
+    
     @Override
     public String getFamily()
     {
@@ -72,6 +73,19 @@ public class MenuListTag extends UIOutput implements TagEncodingHolder
     {
         return helper;
     }
+    
+    @Override
+    public boolean isRendered()
+    {
+        // call base for default
+        if (!super.isRendered())
+            return false;
+        // detect if not already detected
+        if (cachedIsRendered== null)
+            cachedIsRendered = isRenderList();
+        // render
+        return cachedIsRendered;
+    }
         
     @Override
     public void encodeBegin(FacesContext context)
@@ -80,7 +94,7 @@ public class MenuListTag extends UIOutput implements TagEncodingHolder
         // call base
         super.encodeBegin(context);
         
-        initMenuAttributes(context);
+        initMenuAttributes();
 
         // render components
         ResponseWriter writer = context.getResponseWriter();
@@ -119,51 +133,16 @@ public class MenuListTag extends UIOutput implements TagEncodingHolder
         writer.endElement("ul");
     }
     
-    protected void initMenuAttributes(FacesContext context)
-    {        
-        currentId        = helper.getTagAttributeString(MenuProperty.currentId.name()); 
-        currentClass     = helper.getTagAttributeString(MenuProperty.currentClass.name()); 
-        parentClass      = helper.getTagAttributeString(MenuProperty.parentClass.name());
-        disabledClass    = helper.getTagAttributeString(MenuProperty.disabledClass.name()); 
-        expandedClass    = helper.getTagAttributeString(MenuProperty.expandedClass.name());
-        itemWrapTag      = helper.getTagAttributeString(MenuProperty.itemWrapTag.name());
-        defaultItemClass = helper.getTagAttributeString(MenuProperty.defaultItemClass.name());
-
-        // find parent
+    public Object getAttribute(String attributeName)
+    {
+        return helper.getTagAttributeValue(attributeName);
+    }
+    
+    public final MenuListTag getParentMenu()
+    {
         if (parentMenu==null)
             parentMenu = findParentMenu();
-        if (parentMenu==null)
-        {   // the root menu
-            if (currentClass==null)
-                currentClass = "current";  
-            if (parentClass==null)
-                parentClass = "parent";
-            if (disabledClass==null)
-                disabledClass = "parent";
-            if (expandedClass==null)
-                expandedClass = "expanded";
-            // level
-            level = 0;
-        }
-        else
-        {   // copy from parent
-            if (currentId==null)
-                currentId = parentMenu.getCurrentItemId();
-            if (currentClass==null)
-                currentClass = parentMenu.getCurrentItemClass();  
-            if (parentClass==null)
-                parentClass = parentMenu.getParentItemClass();
-            if (disabledClass==null)
-                disabledClass = parentMenu.getItemDisabledClass();
-            if (expandedClass==null)
-                expandedClass = parentMenu.getItemExpandedClass();
-            if (itemWrapTag==null)
-                itemWrapTag = parentMenu.getItemWrapperTagName();
-            if (defaultItemClass==null)
-                defaultItemClass = parentMenu.defaultItemClass;
-            // increase level
-            level = parentMenu.level + 1;
-        }
+        return parentMenu;
     }
     
     public String getCurrentItemId()
@@ -219,100 +198,76 @@ public class MenuListTag extends UIOutput implements TagEncodingHolder
         return defaultItemClass;
     }
 
-    /* 
-     * Getters and setter with getStateHelper()
-     * Removed with EMPIREDB-441 on 2024-10-12
-     * 
+    /*
+     * helpers
+     */
     
-    public String getCurrentItemId()
-    {
-        if (currentId==null)
-            currentId= StringUtils.toString(getStateHelper().get(MenuProperty.currentId));
-        return currentId;
-    }
-
-    public String getCurrentItemClass()
-    {
-        if (currentClass==null)
-            currentClass= StringUtils.toString(getStateHelper().get(MenuProperty.currentClass));
-        return currentClass;
-    }
-
-    public String getParentItemClass()
-    {
-        if (parentClass==null)
-            parentClass= StringUtils.toString(getStateHelper().get(MenuProperty.parentClass));
-        return parentClass;
-    }
-
-    public String getItemDisabledClass()
-    {
-        if (disabledClass==null)
-            disabledClass= StringUtils.toString(getStateHelper().get(MenuProperty.disabledClass));
-        return disabledClass;
-    }
-
-    public String getItemExpandedClass()
-    {
-        if (expandedClass==null)
-            expandedClass= StringUtils.toString(getStateHelper().get(MenuProperty.expandedClass));
-        return expandedClass;
-    }
-
-    public String getItemWrapperTagName()
+    /**
+     * Returns whether or not the MenuList should be rendered
+     * Override this to implement custom logic
+     * @return true if the menu item should be rendered or false otherwise
+     */
+    protected boolean isRenderList()
     {
-        if (itemWrapTag==null)
-            itemWrapTag= StringUtils.toString(getStateHelper().get(MenuProperty.itemWrapTag));
-        return itemWrapTag;
+        /*
+         * Example implementation for derived classes
+         * 
+        // check whether to render the menu list
+        FacesContext fc = FacesContext.getCurrentInstance();
+        UIViewRoot vr = (fc!=null ? fc.getViewRoot() : null);
+        Map<String, Object> vm = (vr!=null ? vr.getViewMap(false) : null);
+        Page page = (Page) (vm!=null ?  vm.get("page") : null);
+        if (page!=null && !page.isRenderMenuList(this))
+            return false;
+         */    
+        // yes, render
+        return true;
     }
     
-    public void setCurrentId(String currentId)
-    {
-        this.currentId = currentId;
-        // save
-        getStateHelper().put(MenuProperty.currentId, currentId);
-    }
-
-    public void setCurrentClass(String currentClass)
-    {
-        this.currentClass = currentClass;
-        // save
-        getStateHelper().put(MenuProperty.currentClass, currentClass);
-    }
-
-    public void setDisabledClass(String disabledClass)
-    {
-        this.disabledClass = disabledClass;
-        // save
-        getStateHelper().put(MenuProperty.disabledClass, disabledClass);
-    }
-
-    public void setParentClass(String parentClass)
-    {
-        this.parentClass = parentClass;
-        // save
-        getStateHelper().put(MenuProperty.parentClass, parentClass);
-    }
-
-    public void setExpandedClass(String expandedClass)
-    {
-        this.expandedClass = expandedClass;
-        // save
-        getStateHelper().put(MenuProperty.expandedClass, expandedClass);
-    }
+    protected void initMenuAttributes()
+    {        
+        currentId        = helper.getTagAttributeString(MenuProperty.currentId.name()); 
+        currentClass     = helper.getTagAttributeString(MenuProperty.currentClass.name()); 
+        parentClass      = helper.getTagAttributeString(MenuProperty.parentClass.name());
+        disabledClass    = helper.getTagAttributeString(MenuProperty.disabledClass.name()); 
+        expandedClass    = helper.getTagAttributeString(MenuProperty.expandedClass.name());
+        itemWrapTag      = helper.getTagAttributeString(MenuProperty.itemWrapTag.name());
+        defaultItemClass = helper.getTagAttributeString(MenuProperty.defaultItemClass.name());
 
-    public void setItemWrapTag(String itemWrapTag)
-    {
-        this.itemWrapTag = itemWrapTag;
-        // save
-        getStateHelper().put(MenuProperty.itemWrapTag, itemWrapTag);
+        // find parent
+        if (getParentMenu()==null)
+        {   // the root menu
+            if (currentClass==null)
+                currentClass = "current";  
+            if (parentClass==null)
+                parentClass = "parent";
+            if (disabledClass==null)
+                disabledClass = "parent";
+            if (expandedClass==null)
+                expandedClass = "expanded";
+            // level
+            level = 0;
+        }
+        else
+        {   // copy from parent
+            if (currentId==null)
+                currentId = parentMenu.getCurrentItemId();
+            if (currentClass==null)
+                currentClass = parentMenu.getCurrentItemClass();  
+            if (parentClass==null)
+                parentClass = parentMenu.getParentItemClass();
+            if (disabledClass==null)
+                disabledClass = parentMenu.getItemDisabledClass();
+            if (expandedClass==null)
+                expandedClass = parentMenu.getItemExpandedClass();
+            if (itemWrapTag==null)
+                itemWrapTag = parentMenu.getItemWrapperTagName();
+            if (defaultItemClass==null)
+                defaultItemClass = parentMenu.defaultItemClass;
+            // increase level
+            level = parentMenu.level + 1;
+        }
     }
-    
-    */
-
-    /*
-     * helpers
-     */
 
     protected MenuListTag findParentMenu()
     {