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

doebele 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 1cd01500 EMPIREDB-441 TagEncodingHelper code cleanup
1cd01500 is described below

commit 1cd015004a22e45a863c7cf71c6ef21255a90544
Author: Rainer Döbele <[email protected]>
AuthorDate: Sun Oct 13 01:30:36 2024 +0200

    EMPIREDB-441
    TagEncodingHelper code cleanup
---
 .../empire/jakarta/components/FormGridTag.java     |  18 +-
 .../apache/empire/jakarta/components/LinkTag.java  |  82 ++--
 .../empire/jakarta/components/MenuItemTag.java     |  73 +--
 .../empire/jakarta/components/MenuListTag.java     | 108 +++--
 .../empire/jakarta/components/SelectTag.java       |   4 +-
 .../empire/jakarta/components/TabViewTag.java      |  12 +-
 .../empire/jakarta/utils/ControlRenderInfo.java    |  10 +-
 .../empire/jakarta/utils/TagEncodingHelper.java    | 501 +++++++++++----------
 .../apache/empire/jsf2/components/FormGridTag.java |  10 +-
 .../apache/empire/jsf2/components/MenuItemTag.java |  24 +-
 .../apache/empire/jsf2/components/MenuListTag.java | 108 +++--
 .../apache/empire/jsf2/components/TabViewTag.java  |  12 +-
 .../empire/jsf2/utils/ControlRenderInfo.java       |  10 +-
 .../empire/jsf2/utils/TagEncodingHelper.java       | 455 ++++++++++---------
 .../org/apache/empire/commons/StringUtils.java     |   4 +-
 15 files changed, 765 insertions(+), 666 deletions(-)

diff --git 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/FormGridTag.java
 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/FormGridTag.java
index 67983f7c..7eba469a 100644
--- 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/FormGridTag.java
+++ 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/FormGridTag.java
@@ -20,7 +20,6 @@ package org.apache.empire.jakarta.components;
 
 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.utils.ControlRenderInfo;
@@ -112,14 +111,21 @@ public class FormGridTag extends UIOutput // implements 
NamingContainer
             {   // label facet
                 placeholderFacet.encodeAll(context);
             }
-            else if (renderPlaceholder)
+            else if (renderPlaceholder || isRenderPlaceholder(controlTag))
             {   // render placeholder   
                 ResponseWriter writer = context.getResponseWriter();
                 String placeholderTag = (CONTROL_TAG!=null ? CONTROL_TAG : 
INPUT_WRAPPER_TAG);
                 writer.startElement(placeholderTag, controlTag);
-                writer.writeAttribute(InputControl.HTML_ATTR_CLASS, 
TagStyleClass.CONTROL_PLACEHOLDER.get(), null);
-                if (InputControl.HTML_TAG_TD.equalsIgnoreCase(placeholderTag))
+                // id attribute
+                if (CONTROL_TAG!=null && 
TagEncodingHelper.hasComponentId(controlTag))
+                    writer.writeAttribute(InputControl.HTML_ATTR_ID, 
controlTag.getClientId(), null);
+                // Style class
+                String controlStyle = 
controlTag.helper.getTagAttributeString(InputControl.CSS_STYLE_CLASS);
+                controlTag.helper.writeStyleClass(writer, 
TagStyleClass.CONTROL_PLACEHOLDER.get(), controlStyle);
+                // Legacy two <td>
+                if (CONTROL_TAG==null && 
InputControl.HTML_TAG_TD.equalsIgnoreCase(placeholderTag))
                     writer.writeAttribute("colspan", 2, null);
+                // done
                 writer.endElement(placeholderTag);
             }
         }
@@ -203,8 +209,8 @@ public class FormGridTag extends UIOutput // implements 
NamingContainer
                 log.warn("FormGridTag: Invalid value \"{}\" for attribute 
\"autoControlId\". Allowed values are *|@|&", id);
         }
         // create control info
-        UIComponent placeholderFacet = getFacet("placeholder");
-        boolean renderPlaceholder = (placeholderFacet==null ? 
ObjectUtils.getBoolean(getAttributes().get("placeholder"), false) : false);
+        UIComponent placeholderFacet = 
getFacet(ControlRenderInfo.PLACEHOLDER_ATTRIBUTE);
+        boolean renderPlaceholder = (placeholderFacet==null ? 
ControlRenderInfo.isRenderPlaceholder(this) : false);
         this.controlRenderInfo = new FromGridRenderInfo(mode, 
placeholderFacet, renderPlaceholder, autoControlId);
         return controlRenderInfo;
     }
diff --git 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/LinkTag.java
 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/LinkTag.java
index e383cbf7..af960990 100644
--- 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/LinkTag.java
+++ 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/LinkTag.java
@@ -22,20 +22,9 @@ import java.io.IOException;
 import java.util.List;
 import java.util.Map;
 
-import jakarta.faces.component.UIComponent;
-import jakarta.faces.component.UINamingContainer;
-import jakarta.faces.component.UIOutput;
-import jakarta.faces.component.UIPanel;
-import jakarta.faces.component.UIParameter;
-import jakarta.faces.component.html.HtmlGraphicImage;
-import jakarta.faces.component.html.HtmlOutcomeTargetLink;
-import jakarta.faces.component.visit.VisitCallback;
-import jakarta.faces.component.visit.VisitContext;
-import jakarta.faces.context.FacesContext;
-import jakarta.faces.context.ResponseWriter;
-
 import org.apache.empire.commons.ObjectUtils;
 import org.apache.empire.commons.StringUtils;
+import org.apache.empire.exceptions.InvalidArgumentException;
 import org.apache.empire.exceptions.InvalidPropertyException;
 import org.apache.empire.jakarta.app.FacesUtils;
 import org.apache.empire.jakarta.controls.InputControl;
@@ -48,6 +37,18 @@ import org.apache.empire.jakarta.utils.TagStyleClass;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import jakarta.faces.component.UIComponent;
+import jakarta.faces.component.UINamingContainer;
+import jakarta.faces.component.UIOutput;
+import jakarta.faces.component.UIPanel;
+import jakarta.faces.component.UIParameter;
+import jakarta.faces.component.html.HtmlGraphicImage;
+import jakarta.faces.component.html.HtmlOutcomeTargetLink;
+import jakarta.faces.component.visit.VisitCallback;
+import jakarta.faces.component.visit.VisitContext;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.context.ResponseWriter;
+
 public class LinkTag extends UIOutput // implements NamingContainer
 {
     // or HtmlOutcomeTargetLink
@@ -173,10 +174,10 @@ public class LinkTag extends UIOutput // implements 
NamingContainer
                     UIPanel facetComponent = 
(UIPanel)getFacets().get(UIComponent.COMPOSITE_FACET_NAME);
                     if (facetComponent==null)
                     {
-                        log.warn("WARN: component's facetComponent has not 
been set! Using Default (jakarta.faces.Panel).");
+                        log.warn("WARN: component's facetComponent has not 
been set! Using Default (javax.faces.Panel).");
                         log.warn("Problem might be related to Mojarra's state 
context saving for dynamic components (affects all versions > 2.1.6). See 
com.sun.faces.context.StateContext.java:AddRemoveListener");
-                        facetComponent = 
(UIPanel)context.getApplication().createComponent("jakarta.faces.Panel");
-                        facetComponent.setRendererType("jakarta.faces.Group");
+                        facetComponent = 
(UIPanel)context.getApplication().createComponent("javax.faces.Panel");
+                        facetComponent.setRendererType("javax.faces.Group");
                         getFacets().put(UIComponent.COMPOSITE_FACET_NAME, 
facetComponent);
                     }
                 }    
@@ -202,7 +203,7 @@ public class LinkTag extends UIOutput // implements 
NamingContainer
             }
             // set params
             setLinkProperties(linkComponent);
-            addOrSetParam(linkComponent, "idparam", "id");
+            addOrSetParams(linkComponent);
             // encode link
             this.encodeLinkChildren = 
isEncodeLinkChildren(linkComponent.getChildCount()>0 ? null : 
linkComponent.getValue());
             if (this.encodeLinkChildren)
@@ -210,7 +211,7 @@ public class LinkTag extends UIOutput // implements 
NamingContainer
             else
             {   // default rendering (no children)
                 linkComponent.setRendered(true);
-                linkComponent.encodeAll(context);
+                encodeLinkComponent(context, linkComponent);
                 linkComponent.setRendered(false); // Don't render twice!
             }
         }
@@ -333,13 +334,19 @@ public class LinkTag extends UIOutput // implements 
NamingContainer
         // include view param
         link.setIncludeViewParams(false);
     }
+
+    protected void addOrSetParams(HtmlOutcomeTargetLink link)
+    {
+        addOrSetParam(link, "id", 
StringUtils.toString(getAttributes().get("idparam")));
+    }
     
-    protected void addOrSetParam(HtmlOutcomeTargetLink link, String attribute, 
String paramName)
+    protected void addOrSetParam(HtmlOutcomeTargetLink link, String paramName, 
String paramValue)
     {
-        // Get Attribute
-        String paramValue = 
StringUtils.toString(getAttributes().get(attribute));
+        // Check params
         if (StringUtils.isEmpty(paramValue))
-            return; 
+            return; // nothing to do 
+        if (paramName==null || paramName.length()==0)
+            throw new InvalidArgumentException("paramName", paramName);
         // find attribute
         List<UIComponent> l = link.getChildren();
         for (UIComponent c : l)
@@ -384,35 +391,26 @@ public class LinkTag extends UIOutput // implements 
NamingContainer
         return link;
     }
     
-    protected HtmlGraphicImage encodeImage(FacesContext context, 
HtmlOutcomeTargetLink parent, String imagePath)
+    protected HtmlOutcomeTargetLink getLinkComponent()
     {
-        HtmlGraphicImage img = InputControlManager.createComponent(context, 
HtmlGraphicImage.class);
-        img.setValue(imagePath);
-        return img;
+        return (getChildCount()>0 ? 
(HtmlOutcomeTargetLink)getChildren().get(0) : null);
     }
     
-    /*
-     * public String getLabelValue()
-     * {
-     * return StringUtils.toString(getValue());
-     * }
-     * public String getPageValue()
-     * {
-     * return (String) getAttributes().get("page");
-     * }
-     * public String getActionValue()
-     * {
-     * return (String) getAttributes().get("action");
-     * }
-     */
-    
     protected boolean isEncodeLinkChildren(Object linkValue)
     {
         return ObjectUtils.isEmpty(linkValue);
     }
     
-    protected HtmlOutcomeTargetLink getLinkComponent()
+    protected void encodeLinkComponent(FacesContext context, 
HtmlOutcomeTargetLink linkComponent)
+        throws IOException
     {
-        return (getChildCount()>0 ? 
(HtmlOutcomeTargetLink)getChildren().get(0) : null);
+        linkComponent.encodeAll(context);
+    }
+    
+    protected HtmlGraphicImage encodeImage(FacesContext context, 
HtmlOutcomeTargetLink parent, String imagePath)
+    {
+        HtmlGraphicImage img = InputControlManager.createComponent(context, 
HtmlGraphicImage.class);
+        img.setValue(imagePath);
+        return img;
     }
 }
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 a746c83f..550beb15 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
@@ -20,12 +20,6 @@ package org.apache.empire.jakarta.components;
 
 import java.io.IOException;
 
-import jakarta.faces.component.UIComponent;
-import jakarta.faces.component.UINamingContainer;
-import jakarta.faces.component.html.HtmlOutcomeTargetLink;
-import jakarta.faces.context.FacesContext;
-import jakarta.faces.context.ResponseWriter;
-
 import org.apache.empire.commons.ObjectUtils;
 import org.apache.empire.commons.StringUtils;
 import org.apache.empire.jakarta.controls.InputControl;
@@ -33,6 +27,12 @@ import org.apache.empire.jakarta.utils.TagEncodingHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import jakarta.faces.component.UIComponent;
+import jakarta.faces.component.UINamingContainer;
+import jakarta.faces.component.html.HtmlOutcomeTargetLink;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.context.ResponseWriter;
+
 public class MenuItemTag extends LinkTag
 {
     // Logger
@@ -116,7 +116,7 @@ public class MenuItemTag extends LinkTag
         helper.writeAttribute(writer, "class", getStyleClass());
 
         // wrap
-        String wrap = (parentMenu!=null ? parentMenu.getItemWrapTag() : null);
+        String wrap = (parentMenu!=null ? parentMenu.getItemWrapperTagName() : 
null);
         if (StringUtils.isNotEmpty(wrap))
         {   // Wrap-Element
             writer.startElement(wrap, this);
@@ -173,19 +173,6 @@ public class MenuItemTag extends LinkTag
         ResponseWriter writer = context.getResponseWriter();
         writer.endElement("li");
     }
-    
-    /*
-    private void printChildTree(UIComponent comp, int level)
-    {
-        List<UIComponent> cl = comp.getChildren();
-        for (UIComponent c : cl)
-        {
-            boolean isRendered = c.isRendered();
-            log.info("-{}- rendering {} "+String.valueOf(isRendered), level, 
c.getClass().getSimpleName());
-            printChildTree(c, level+1);
-        }
-    }
-    */
 
     @Override
     protected String getLinkStyleClass()
@@ -211,18 +198,18 @@ public class MenuItemTag extends LinkTag
     
     protected boolean isCurrent()
     {
-        if (menuId==null || parentMenu==null || 
parentMenu.getCurrentId()==null)
+        if (menuId==null || parentMenu==null || 
parentMenu.getCurrentItemId()==null)
             return false;
         // All present
-        return menuId.equals(parentMenu.getCurrentId());
+        return menuId.equals(parentMenu.getCurrentItemId());
     }
     
     protected boolean isParent()
     {
-        if (menuId==null || parentMenu==null || 
parentMenu.getCurrentId()==null)
+        if (menuId==null || parentMenu==null || 
parentMenu.getCurrentItemId()==null)
             return false;
         // All present
-        String  currentId = parentMenu.getCurrentId();
+        String  currentId = parentMenu.getCurrentItemId();
         return (currentId.length()>menuId.length() && 
currentId.startsWith(menuId));
     }
 
@@ -248,10 +235,10 @@ public class MenuItemTag extends LinkTag
                 return true;
         }
         // Check parent
-        if (menuId==null || parentMenu==null || 
parentMenu.getCurrentId()==null)
+        if (menuId==null || parentMenu==null || 
parentMenu.getCurrentItemId()==null)
             return auto;
         // All present
-        String currentId = parentMenu.getCurrentId();
+        String currentId = parentMenu.getCurrentItemId();
         return currentId.startsWith(menuId+".");
     }
     
@@ -264,7 +251,7 @@ public class MenuItemTag extends LinkTag
             currentOnly = ObjectUtils.getBoolean(value);
         
         // Check parent
-        if (currentOnly && menuId!=null && parentMenu!=null && 
parentMenu.getCurrentId()!=null)
+        if (currentOnly && menuId!=null && parentMenu!=null && 
parentMenu.getCurrentItemId()!=null)
         {    
             return isCurrent() || isParent();
         }
@@ -282,15 +269,15 @@ public class MenuItemTag extends LinkTag
                 styleClass = parentMenu.getItemStyleClass();
             // Menu Class
             if (isCurrent())
-                styleClass = appendStyleClass(styleClass, 
parentMenu.getCurrentClass());
+                styleClass = appendStyleClass(styleClass, 
parentMenu.getCurrentItemClass());
             else if (isParent())
-                styleClass = appendStyleClass(styleClass, 
parentMenu.getParentClass());
+                styleClass = appendStyleClass(styleClass, 
parentMenu.getParentItemClass());
             // expanded
             if (isExpanded())
-                styleClass = appendStyleClass(styleClass, 
parentMenu.getExpandedClass());            
+                styleClass = appendStyleClass(styleClass, 
parentMenu.getItemExpandedClass());            
             // Disabled / enabled
             if (isDisabled())
-                styleClass = appendStyleClass(styleClass, 
parentMenu.getDisabledClass());
+                styleClass = appendStyleClass(styleClass, 
parentMenu.getItemDisabledClass());
         }
         else
         {   // disabled
@@ -313,4 +300,28 @@ public class MenuItemTag extends LinkTag
     {
         return false;
     }
+
+    
+    /* 
+     * Supports a "label" facet" e.g.
+     * <e:mitem menuId="..." page="..."><f:facet name="label"><span 
class="icon"/><label>...</label></f:facet></e:mitem>
+     */ 
+    
+    @Override
+    protected void encodeLinkComponent(FacesContext context, 
HtmlOutcomeTargetLink linkComponent)
+        throws IOException
+    {
+        UIComponent labelFacet = this.getFacet("label");
+        if (labelFacet!=null)
+        {   // custom rendering
+            linkComponent.encodeBegin(context);
+            labelFacet.encodeAll(context);
+            linkComponent.encodeEnd(context);
+        }
+        else
+        {   // default
+            linkComponent.encodeAll(context);
+        }
+    }
+    
 }
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 d111fc0b..5e3303b2 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
@@ -48,7 +48,6 @@ public class MenuListTag extends UIOutput // implements 
NamingContainer
         expandedClass,
         itemWrapTag,
         defaultItemClass;
-        // autoItemId
     }
     
     protected String currentId = null; 
@@ -58,7 +57,6 @@ public class MenuListTag extends UIOutput // implements 
NamingContainer
     protected String expandedClass = null;
     protected String itemWrapTag = null;
     protected String defaultItemClass = null; // e.g. "level{}"
-    // protected Boolean autoItemId = null;
     protected int level = 0;
     
     private MenuListTag parentMenu = null; 
@@ -144,17 +142,17 @@ public class MenuListTag extends UIOutput // implements 
NamingContainer
         else
         {   // copy from parent
             if (currentId==null)
-                currentId = parentMenu.getCurrentId();
+                currentId = parentMenu.getCurrentItemId();
             if (currentClass==null)
-                currentClass = parentMenu.getCurrentClass();  
+                currentClass = parentMenu.getCurrentItemClass();  
             if (parentClass==null)
-                parentClass = parentMenu.getParentClass();
+                parentClass = parentMenu.getParentItemClass();
             if (disabledClass==null)
-                disabledClass = parentMenu.getDisabledClass();
+                disabledClass = parentMenu.getItemDisabledClass();
             if (expandedClass==null)
-                expandedClass = parentMenu.getExpandedClass();
+                expandedClass = parentMenu.getItemExpandedClass();
             if (itemWrapTag==null)
-                itemWrapTag = parentMenu.getItemWrapTag();
+                itemWrapTag = parentMenu.getItemWrapperTagName();
             if (defaultItemClass==null)
                 defaultItemClass = parentMenu.defaultItemClass;
             // increase level
@@ -162,45 +160,33 @@ public class MenuListTag extends UIOutput // implements 
NamingContainer
         }
     }
     
-    public String getCurrentId()
+    public String getCurrentItemId()
     {
-        if (currentId==null)
-            currentId= 
StringUtils.toString(getStateHelper().get(MenuProperty.currentId));
         return currentId;
     }
 
-    public String getCurrentClass()
+    public String getCurrentItemClass()
     {
-        if (currentClass==null)
-            currentClass= 
StringUtils.toString(getStateHelper().get(MenuProperty.currentClass));
         return currentClass;
     }
 
-    public String getDisabledClass()
+    public String getParentItemClass()
     {
-        if (disabledClass==null)
-            disabledClass= 
StringUtils.toString(getStateHelper().get(MenuProperty.disabledClass));
-        return disabledClass;
+        return parentClass;
     }
 
-    public String getParentClass()
+    public String getItemDisabledClass()
     {
-        if (parentClass==null)
-            parentClass= 
StringUtils.toString(getStateHelper().get(MenuProperty.parentClass));
-        return parentClass;
+        return disabledClass;
     }
 
-    public String getExpandedClass()
+    public String getItemExpandedClass()
     {
-        if (expandedClass==null)
-            expandedClass= 
StringUtils.toString(getStateHelper().get(MenuProperty.expandedClass));
         return expandedClass;
     }
 
-    public String getItemWrapTag()
+    public String getItemWrapperTagName()
     {
-        if (itemWrapTag==null)
-            itemWrapTag= 
StringUtils.toString(getStateHelper().get(MenuProperty.itemWrapTag));
         return itemWrapTag;
     }
     
@@ -226,24 +212,53 @@ public class MenuListTag extends UIOutput // implements 
NamingContainer
         // return default
         return defaultItemClass;
     }
+
+    /* 
+     * Getters and setter with getStateHelper()
+     * Removed with EMPIREDB-441 on 2024-10-12
+     * 
     
-    /*
-    public Boolean isAutoItemId()
+    public String getCurrentItemId()
     {
-        if (this.autoItemId == null) {
-            this.autoItemId = 
(Boolean)getStateHelper().get(Properties.autoItemId);
-            if (this.autoItemId==null) {
-                if (parentMenu==null)
-                    parentMenu = findParentMenu();
-                if (parentMenu!=null)
-                    return parentMenu.isAutoItemId();
-            }
-        }
-        return this.autoItemId;
+        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;
     }
-    */
 
-    /* setters */
+    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()
+    {
+        if (itemWrapTag==null)
+            itemWrapTag= 
StringUtils.toString(getStateHelper().get(MenuProperty.itemWrapTag));
+        return itemWrapTag;
+    }
     
     public void setCurrentId(String currentId)
     {
@@ -286,14 +301,7 @@ public class MenuListTag extends UIOutput // implements 
NamingContainer
         // save
         getStateHelper().put(MenuProperty.itemWrapTag, itemWrapTag);
     }
-
-    /*
-    public void setAutoItemId(Boolean autoItemId)
-    {
-        this.autoItemId = autoItemId;
-        // save
-        getStateHelper().put(Properties.autoItemId, this.autoItemId);
-    }
+    
     */
 
     /*
diff --git 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/SelectTag.java
 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/SelectTag.java
index 01e7c694..726c1fd0 100644
--- 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/SelectTag.java
+++ 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/SelectTag.java
@@ -408,9 +408,9 @@ public class SelectTag extends UIInput implements 
NamingContainer
     protected void copyAttributes(UISelectOne input)
     {
         // set id
-        String inputId = this.getId();
-        if (TagEncodingHelper.hasComponentId(inputId))
+        if (TagEncodingHelper.hasComponentId(this))
         {   // remove trailing underscore (workaround since parent and child 
may not have the same name)
+            String inputId = this.getId();
             if (inputId.endsWith("_"))
             {
                 inputId = inputId.substring(0, inputId.length() - 1);
diff --git 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/TabViewTag.java
 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/TabViewTag.java
index 138a502e..5a7b058f 100644
--- 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/TabViewTag.java
+++ 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/components/TabViewTag.java
@@ -236,7 +236,7 @@ public class TabViewTag extends UIOutput // implements 
NamingContainer
 
         // The Blind
         String showTabBlindJs = null;
-        if 
(ObjectUtils.getBoolean(this.helper.getTagAttributeValue("showBlind")))
+        if (ObjectUtils.getBoolean(helper.getTagAttributeValue("showBlind")))
         {   // hide bar
             String tabBlindClass = TagStyleClass.TAB_BLIND.get();
             writer.startElement(InputControl.HTML_TAG_DIV, this);
@@ -384,7 +384,7 @@ public class TabViewTag extends UIOutput // implements 
NamingContainer
             }
             if (writer!=null)
             {   // encode Tab
-                boolean disabled = 
ObjectUtils.getBoolean(TagEncodingHelper.getTagAttributeValue(page, 
"disabled"));
+                boolean disabled = isPageDisabled(page);
                 writer.startElement(mode.BAR_ITEM_TAG, this);
                 // tab label
                 String styleClasses = TagStyleClass.TAB_LABEL.get();
@@ -491,6 +491,12 @@ public class TabViewTag extends UIOutput // implements 
NamingContainer
     
     protected boolean isPageVisible(TabPageTag page)
     {
-        return 
ObjectUtils.getBoolean(ObjectUtils.coalesce(page.getAttributes().get(this.TAB_RENDERED_ATTRIBUTE),
 true));
+        return 
ObjectUtils.getBoolean(page.getAttributes().get(this.TAB_RENDERED_ATTRIBUTE), 
true);
     }
+    
+    protected boolean isPageDisabled(TabPageTag page)
+    {
+        return ObjectUtils.getBoolean(page.getAttributes().get("disabled"), 
false);
+    }
+    
 }
diff --git 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/ControlRenderInfo.java
 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/ControlRenderInfo.java
index d5df3d7f..3cf341ce 100644
--- 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/ControlRenderInfo.java
+++ 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/ControlRenderInfo.java
@@ -25,6 +25,7 @@ import org.apache.empire.commons.StringUtils;
 import org.apache.empire.jakarta.components.ControlTag;
 import org.apache.empire.jakarta.controls.InputControl;
 
+import jakarta.faces.component.UIComponent;
 import jakarta.faces.context.FacesContext;
 import jakarta.faces.context.ResponseWriter;
 
@@ -37,6 +38,8 @@ public class ControlRenderInfo
      * Use setDefault(ControlRenderInfo renderInfo) in order to change the 
default
      */
     private static ControlRenderInfo DEFAULT_CONTROL_RENDER_INFO = new 
DefaultControlRenderInfo();
+    
+    public static final String PLACEHOLDER_ATTRIBUTE = "placeholder";
 
     public static ControlRenderInfo getDefault()
     {
@@ -48,6 +51,11 @@ public class ControlRenderInfo
         DEFAULT_CONTROL_RENDER_INFO = renderInfo;
     }
     
+    public static boolean isRenderPlaceholder(UIComponent component)
+    {
+        return 
ObjectUtils.getBoolean(component.getAttributes().get(PLACEHOLDER_ATTRIBUTE), 
false);        
+    }
+    
     private static class DefaultControlRenderInfo extends ControlRenderInfo
     {
         public DefaultControlRenderInfo()
@@ -60,7 +68,7 @@ public class ControlRenderInfo
             throws IOException
         {
             // check attribute "placeholder"
-            if 
(ObjectUtils.getBoolean(controlTag.getAttributes().get("placeholder"), false))
+            if (isRenderPlaceholder(controlTag))
             {   // render placeholder for invisible controls 
                 ResponseWriter writer = context.getResponseWriter();
                 writer.startElement(InputControl.HTML_TAG_TD, controlTag);
diff --git 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/TagEncodingHelper.java
 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/TagEncodingHelper.java
index 539e21e2..9d6a9150 100644
--- 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/TagEncodingHelper.java
+++ 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/TagEncodingHelper.java
@@ -25,20 +25,6 @@ import java.util.Iterator;
 import java.util.Locale;
 import java.util.Set;
 
-import jakarta.el.ValueExpression;
-import jakarta.faces.FacesWrapper;
-import jakarta.faces.application.FacesMessage;
-import jakarta.faces.component.NamingContainer;
-import jakarta.faces.component.UIComponent;
-import jakarta.faces.component.UIData;
-import jakarta.faces.component.UIInput;
-import jakarta.faces.component.UIOutput;
-import jakarta.faces.component.html.HtmlOutputLabel;
-import jakarta.faces.component.html.HtmlOutputText;
-import jakarta.faces.component.html.HtmlPanelGroup;
-import jakarta.faces.context.FacesContext;
-import jakarta.faces.context.ResponseWriter;
-
 import org.apache.commons.beanutils.BeanUtils;
 import org.apache.commons.beanutils.BeanUtilsBean;
 import org.apache.commons.beanutils.PropertyUtils;
@@ -76,15 +62,33 @@ import org.apache.empire.jakarta.components.LabelTag;
 import org.apache.empire.jakarta.components.LinkTag;
 import org.apache.empire.jakarta.components.RecordTag;
 import org.apache.empire.jakarta.controls.InputControl;
-import org.apache.empire.jakarta.controls.InputControlManager;
-import org.apache.empire.jakarta.controls.SelectInputControl;
-import org.apache.empire.jakarta.controls.TextInputControl;
 import org.apache.empire.jakarta.controls.InputControl.DisabledType;
 import org.apache.empire.jakarta.controls.InputControl.InputInfo;
 import org.apache.empire.jakarta.controls.InputControl.ValueInfo;
+import org.apache.empire.jakarta.controls.InputControlManager;
+import org.apache.empire.jakarta.controls.SelectInputControl;
+import org.apache.empire.jakarta.controls.TextInputControl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import jakarta.el.ValueExpression;
+import jakarta.faces.FacesWrapper;
+import jakarta.faces.application.FacesMessage;
+import jakarta.faces.component.NamingContainer;
+import jakarta.faces.component.UIComponent;
+import jakarta.faces.component.UIData;
+import jakarta.faces.component.UIInput;
+import jakarta.faces.component.UIOutput;
+import jakarta.faces.component.html.HtmlOutputLabel;
+import jakarta.faces.component.html.HtmlOutputText;
+import jakarta.faces.component.html.HtmlPanelGroup;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.context.ResponseWriter;
+
+/**
+ * TagEncodingHelper
+ * Used by all Empire Components to exchange data and render 
+ */
 public class TagEncodingHelper implements NamingContainer
 {
     public static final String FACES_ID_PREFIX = "j_id";  // Standard Faces ID 
Prefix
@@ -418,7 +422,7 @@ public class TagEncodingHelper implements NamingContainer
         @Override
         public Object getAttributeEx(String name)
         {
-            return getAttributeValueEx(name);
+            return getTagAttributeValueEx(name);
         }
     }
 
@@ -549,7 +553,7 @@ public class TagEncodingHelper implements NamingContainer
     {
         // Create
         if (getColumn() == null)
-               throw new NotSupportedException(this, "getInputControl");
+            throw new NotSupportedException(this, "getInputControl");
         // Get Control from column
         String controlType = getTagAttributeString("controlType");
         if (controlType==null)
@@ -812,14 +816,13 @@ public class TagEncodingHelper implements NamingContainer
             if (evalExpression)
                 return component.getValue();
             else
-            {   // return value or value expression
+            {   // Check LocalValue and ValueExpression
                 Object value = component.getLocalValue();
                 if (value!=null && (component instanceof UIInput) && 
!((UIInput)component).isLocalValueSet())
                     value= null; /* should never come here! */
                 if (value==null)
-                    value = findValueExpression("value", false);
-                
-                // value = tag.getValue();
+                    value = findValueExpression("value");
+                // Return the local value or the ValueExpression if any
                 return value;
             }
         }
@@ -937,6 +940,12 @@ public class TagEncodingHelper implements NamingContainer
 
     public boolean isVisible()
     {
+        // check attribute
+        Object val = getTagAttributeValue("visible");
+        if (!ObjectUtils.isEmpty(val))
+        {   // override
+            return ObjectUtils.getBoolean(val);
+        }
         // reset record
         if (this.record!=null)
         {   // Check attribute
@@ -1024,7 +1033,7 @@ public class TagEncodingHelper implements NamingContainer
             return DisabledType.READONLY;
         }
         // Check attribute
-        Object dis = getAttributeValueEx("disabled");
+        Object dis = getTagAttributeValueEx("disabled");
         if (ObjectUtils.isEmpty(dis))
             return null; // not provided!
         // direct
@@ -1214,7 +1223,7 @@ public class TagEncodingHelper implements NamingContainer
         // Find expression
         if (this.hasValueExpr<0)
         {   // Find expression
-            ValueExpression ve = findValueExpression("value", false);
+            ValueExpression ve = findValueExpression("value");
             if (ve != null)
             {   // We have a ValueExpression!
                 // Now unwrap for Facelet-Tags to work
@@ -1233,17 +1242,18 @@ public class TagEncodingHelper implements 
NamingContainer
         }
         return (hasValueExpr>0);
     }
-        
+    
+    // composite component expression
     protected static final String CC_ATTR_EXPR = "#{cc.attrs.";
     
     @SuppressWarnings("unchecked")
-    protected ValueExpression findValueExpression(String attribute, boolean 
allowLiteral)
+    protected ValueExpression findValueExpression(String attribute)
     {
         // Check for expression
         ValueExpression ve = component.getValueExpression(attribute);
         if (ve == null)
             return null;
-        // Find expression
+        // Check for composite component expression
         UIComponent parent = component;
         String expr = ve.getExpressionString();
         while (expr.startsWith(CC_ATTR_EXPR))
@@ -1254,8 +1264,8 @@ public class TagEncodingHelper implements NamingContainer
             // find parent
             UIComponent valueParent = 
FacesUtils.getFacesImplementation().getValueParentComponent(ve);
             if (valueParent!=null)
-            {  // use the value parent
-               parent = valueParent;
+            {   // use the value parent
+                parent = valueParent;
             }
             else
             {   // find parent
@@ -1271,9 +1281,10 @@ public class TagEncodingHelper implements NamingContainer
             // find attribute
             ValueExpression next = parent.getValueExpression(attrib);
             if (next == null)
-            {   // allow literal
+            {   /* allow literal (obsolte 2024-10-12)
                 if (allowLiteral && (parent.getAttributes().get(attrib)!=null))
                     return ve;
+                */    
                 // not found
                 return null;
             }
@@ -1284,34 +1295,6 @@ public class TagEncodingHelper implements NamingContainer
         // found
         return ve;
     }
-    
-    protected final Options getValueOptions()
-    {
-        if (this.optionsDetected==false)
-        {   // detect Options
-            this.options = detectValueOptions();
-            this.optionsDetected = true;
-        }
-        return this.options;
-    }
-    
-    protected Options detectValueOptions()
-    {
-        // null value
-        Object attr = getTagAttributeValue("options");
-        if (attr != null && (attr instanceof Options))
-            return ((Options) attr);
-        if (hasColumn())
-        {   // Do we have a record?
-            Object rec = (this.record!=null ? this.record : findRecord());
-            if ((rec instanceof Record) && ((Record)rec).isValid()) 
-                return ((Record)rec).getFieldOptions(unwrapColumn(column));
-            // get From Column
-            return column.getOptions();
-        }
-        // not available
-        return null;
-    }
 
     protected Object getBeanPropertyValue(Object bean, String property)
     {
@@ -1377,6 +1360,34 @@ public class TagEncodingHelper implements NamingContainer
         }
     }
     
+    protected final Options getValueOptions()
+    {
+        if (this.optionsDetected==false)
+        {   // detect Options
+            this.options = detectValueOptions();
+            this.optionsDetected = true;
+        }
+        return this.options;
+    }
+    
+    protected Options detectValueOptions()
+    {
+        // null value
+        Object attr = getTagAttributeValue("options");
+        if (attr != null && (attr instanceof Options))
+            return ((Options) attr);
+        if (hasColumn())
+        {   // Do we have a record?
+            Object rec = (this.record!=null ? this.record : findRecord());
+            if ((rec instanceof Record) && ((Record)rec).isValid()) 
+                return ((Record)rec).getFieldOptions(unwrapColumn(column));
+            // get From Column
+            return column.getOptions();
+        }
+        // not available
+        return null;
+    }
+    
     public String getValueTooltip(Object value)
     {
         if (value == null)
@@ -1469,6 +1480,8 @@ public class TagEncodingHelper implements NamingContainer
         return textResolver;
     }
     
+    /* ********************** Error messages ********************** */
+    
     protected boolean detectError(FacesContext context)
     {
         Iterator<FacesMessage> iter = 
context.getMessages(component.getClientId());
@@ -1495,175 +1508,6 @@ public class TagEncodingHelper implements 
NamingContainer
         FacesMessage msg = getFieldValueErrorMessage(context, e, value);
         context.addMessage(component.getClientId(), msg);
     }
-
-    public Object getAttributeValueEx(String name)
-    { 
-        Object value = getTagAttributeValue(name);
-        if (value==null && hasColumn())
-        {   // Check Column
-            value = column.getAttribute(name);
-        }
-        // Checks whether it's another column    
-        if (value instanceof Column)
-        {   // Special case: Value is a column
-            Column col = ((Column)value);
-            Object rec = getRecord();
-            if (rec instanceof Record)
-                return ((Record)rec).get(col);
-            else if (rec!=null)
-            {   // Get Value from a bean
-                String property = col.getBeanPropertyName();
-                try
-                {   // Use Beanutils to get Property
-                    PropertyUtilsBean pub = 
BeanUtilsBean.getInstance().getPropertyUtils();
-                    return pub.getSimpleProperty(rec, property);
-                }
-                catch (Exception e)
-                {   log.error("BeanUtils.getSimpleProperty failed for 
"+property, e);
-                    return null;
-                }
-            }    
-            return null;
-        }
-        return value;
-    }
-
-    public String getTagAttributeStringEx(String name)
-    {
-        Object value = getAttributeValueEx(name);
-        return (value!=null) ? StringUtils.nullIfEmpty(value) : null;
-    }
-    
-    public Object getTagAttributeValue(String name)
-    {
-        return TagEncodingHelper.getTagAttributeValue(component, name);
-    }
-    
-    public boolean hasComponentId()
-    {
-        String id = component.getId();
-        return (id!=null && id.length()>0 && !id.startsWith(FACES_ID_PREFIX)); 
       
-    }
-    
-    public static boolean hasComponentId(String id)
-    {
-        return (id!=null && id.length()>0 && !id.startsWith(FACES_ID_PREFIX)); 
       
-    }
-
-    public static Object getTagAttributeValue(UIComponent comp, String name)
-    {
-        Object value = comp.getAttributes().get(name);
-        if (value==null)
-        {   // try value expression
-            ValueExpression ve = comp.getValueExpression(name);
-            if (ve!=null)
-            {   // It's a value expression
-                FacesContext ctx = FacesContext.getCurrentInstance();
-                value = ve.getValue(ctx.getELContext());
-            }
-        }
-        return value;
-    }
-
-    public static String buildComponentId(String s)
-    {
-        if (s==null || s.length()==0)
-            return null;
-        StringBuilder b = new StringBuilder(s.length());
-        for (int i=0; i<s.length(); i++)
-        {
-            char c = s.charAt(i);
-            if (c!='_' && !StringUtils.isCharBetween(c, 'A', 'Z') && 
!StringUtils.isCharBetween(c, 'a', 'z') && !StringUtils.isNumber(c))
-                c='-';
-            b.append(c);
-        }
-        return b.toString();
-    }
-    
-    public String getTagAttributeString(String name, String defValue)
-    {
-        Object value = getTagAttributeValue(name);
-        String sval = StringUtils.nullIfEmpty(value);
-        return (defValue!=null ? StringUtils.coalesce(sval, defValue) : sval);
-    }
-
-    public String getTagAttributeString(String name)
-    {
-        return getTagAttributeString(name, null);
-    }
-
-    public void writeAttribute(ResponseWriter writer, String attribute, Object 
value)
-        throws IOException
-    {
-        if (value != null)
-            writer.writeAttribute(attribute, value, null);
-    }
-    
-    public void writeComponentId(ResponseWriter writer, boolean renderAutoId)
-        throws IOException
-    {
-        // render id
-        if (renderAutoId || hasComponentId())
-            writer.writeAttribute(InputControl.HTML_ATTR_ID, 
component.getClientId(), null);
-    }
-    
-    public void writeComponentId(ResponseWriter writer)
-            throws IOException
-    {
-        writeComponentId(writer, (component instanceof NamingContainer));
-    }
-
-    public void writeStyleClass(ResponseWriter writer, String... styleClasses)
-        throws IOException
-    {
-        // Check if there is only one
-        int i=0;
-        String styleClass = null;
-        for (; i<styleClasses.length; i++) {
-            if (styleClasses[i]!=null) {
-                if (styleClass!=null) {
-                    break; // more than one!
-                }
-                styleClass = styleClasses[i];
-            }
-        }
-        if (i<styleClasses.length)
-            styleClass = StringUtils.arrayToString(styleClasses, 
StringUtils.SPACE, null, true);
-        if (styleClass != null)
-            writer.writeAttribute(InputControl.HTML_ATTR_CLASS, styleClass, 
null);
-    }
-
-    public void writeStyleClass(ResponseWriter writer)
-        throws IOException
-    {
-        String userStyle = 
getTagAttributeStringEx(InputControl.CSS_STYLE_CLASS);
-        writeStyleClass(writer, this.cssStyleClass, userStyle);
-    }
-    
-    public String writeWrapperTag(FacesContext context, boolean renderId, 
boolean renderValue)
-        throws IOException
-    {
-        String wrapperClass = getTagAttributeStringEx("wrapperClass"); 
-        if (wrapperClass==null)
-            return null;
-        // start element
-        String tagName = InputControl.HTML_TAG_DIV;
-        ResponseWriter writer = context.getResponseWriter();
-        writer.startElement(tagName, this.component);
-        // render id
-        if (renderId)
-            writeComponentId(writer);
-        // style class
-        String wrapCtxClass = (renderValue ? "eWrapVal" : "eWrapInp");
-        writeStyleClass(writer, wrapCtxClass, nullIf(wrapperClass, '-'));
-        // return tagName
-        return tagName;
-    }
-
-    protected String nullIf(String value, char nullChar)
-    {
-        return (value==null || value.length()==0 || (value.length()==1 && 
value.charAt(0)==nullChar) ? null : value);   
-    }
     
     /* ********************** FormGridTag ********************** */
 
@@ -1690,7 +1534,7 @@ public class TagEncodingHelper implements NamingContainer
         return (formGrid!=null) ? formGrid.getControlRenderInfo() : null;  
     }
 
-    /* ********************** label ********************** */
+    /* ********************** Label ********************** */
 
     protected String getLabelValue(Column column, boolean colon)
     {
@@ -1743,7 +1587,7 @@ public class TagEncodingHelper implements NamingContainer
             {   // for LabelTag
                 forInput = this.getColumnName();
                 // readOnly
-                Object val = getAttributeValueEx("readOnly");
+                Object val = getTagAttributeValueEx("readOnly");
                 if (val!=null)
                     this.readOnly = (ObjectUtils.getBoolean(val) ? (byte)1 : 
(byte)0);
             }
@@ -1814,7 +1658,7 @@ public class TagEncodingHelper implements NamingContainer
             }
             else if (component instanceof LabelTag)
             {   // update readOnly
-                Object val = getAttributeValueEx("readOnly");
+                Object val = getTagAttributeValueEx("readOnly");
                 if (val!=null)
                     this.readOnly = (ObjectUtils.getBoolean(val) ? (byte)1 : 
(byte)0);
             }
@@ -1975,14 +1819,7 @@ public class TagEncodingHelper implements NamingContainer
         return null;
     }
 
-    public final boolean isInsideUIData()
-    {
-        if (component==null)
-            return false;
-        if (this.insideUIData<0)
-            this.insideUIData=(detectInsideUIData() ? (byte)1 : (byte)0);
-        return (this.insideUIData>0);
-    }
+    /* ********************** UIData detection ********************** */
     
     protected boolean detectInsideUIData()
     {
@@ -2002,6 +1839,43 @@ public class TagEncodingHelper implements NamingContainer
         }
         return false;
     }
+
+    public final boolean isInsideUIData()
+    {
+        if (component==null)
+            return false;
+        if (this.insideUIData<0)
+            this.insideUIData=(detectInsideUIData() ? (byte)1 : (byte)0);
+        return (this.insideUIData>0);
+    }
+    
+    /* ********************** Component id ********************** */
+
+    public static String buildComponentId(String s)
+    {
+        if (s==null || s.length()==0)
+            return null;
+        StringBuilder b = new StringBuilder(s.length());
+        for (int i=0; i<s.length(); i++)
+        {
+            char c = s.charAt(i);
+            if (c!='_' && !StringUtils.isCharBetween(c, 'A', 'Z') && 
!StringUtils.isCharBetween(c, 'a', 'z') && !StringUtils.isNumber(c))
+                c='-';
+            b.append(c);
+        }
+        return b.toString();
+    }
+    
+    public static boolean hasComponentId(UIComponent component)
+    {
+        String id = component.getId();
+        return (id!=null && id.length()>0 && !id.startsWith(FACES_ID_PREFIX)); 
       
+    }
+
+    public boolean hasComponentId()
+    {
+        return hasComponentId(this.component);        
+    }
     
     public void saveComponentId(UIComponent comp)
     {
@@ -2038,5 +1912,154 @@ public class TagEncodingHelper implements 
NamingContainer
             comp.setId(resetId);
         }
     }
+
+    /* ********************** Attribute value ********************** */
+    
+    public Object getTagAttributeValue(String name)
+    {
+        Object value = component.getAttributes().get(name);
+        /*
+         * Removed with EMPIREDB-441 on 2024-10-12
+         * ValueExpression expression is already checked internally by 
getAttributes()
+         * 
+        if (value==null)
+        {   // try value expression
+            ValueExpression ve = component.getValueExpression(name);
+            if (ve!=null)
+            {   // It's a value expression
+                FacesContext ctx = FacesContext.getCurrentInstance();
+                value = ve.getValue(ctx.getELContext());
+            }
+        }
+        */
+        return value;
+    }
+    
+    public String getTagAttributeString(String name, String defValue)
+    {
+        Object value = getTagAttributeValue(name);
+        String sval  = StringUtils.nullIfEmpty(value);
+        return (sval==null ? defValue : sval);
+    }
+
+    public String getTagAttributeString(String name)
+    {
+        return getTagAttributeString(name, null);
+    }
+
+    public Object getTagAttributeValueEx(String name)
+    { 
+        Object value = getTagAttributeValue(name);
+        if (value==null && hasColumn())
+        {   // Check Column
+            value = column.getAttribute(name);
+        }
+        // Checks whether it's another column    
+        if (value instanceof Column)
+        {   // Special case: Value is a column
+            Column col = ((Column)value);
+            Object rec = getRecord();
+            if (rec instanceof Record)
+                return ((Record)rec).get(col);
+            else if (rec!=null)
+            {   // Get Value from a bean
+                String property = col.getBeanPropertyName();
+                try
+                {   // Use Beanutils to get Property
+                    PropertyUtilsBean pub = 
BeanUtilsBean.getInstance().getPropertyUtils();
+                    return pub.getSimpleProperty(rec, property);
+                }
+                catch (Exception e)
+                {   log.error("BeanUtils.getSimpleProperty failed for 
"+property, e);
+                    return null;
+                }
+            }    
+            return null;
+        }
+        return value;
+    }
+
+    public String getTagAttributeStringEx(String name)
+    {
+        Object value = getTagAttributeValueEx(name);
+        return (value!=null) ? StringUtils.nullIfEmpty(value) : null;
+    }
+    
+    /* ********************** Response write helper ********************** */
+    
+    public void writeComponentId(ResponseWriter writer, boolean renderAutoId)
+        throws IOException
+    {
+        // render id
+        if (renderAutoId || hasComponentId())
+            writer.writeAttribute(InputControl.HTML_ATTR_ID, 
component.getClientId(), null);
+    }
+    
+    public void writeComponentId(ResponseWriter writer)
+        throws IOException
+    {
+        writeComponentId(writer, (component instanceof NamingContainer));
+    }
+
+    public void writeAttribute(ResponseWriter writer, String attribute, Object 
value)
+        throws IOException
+    {
+        if (value != null && !ObjectUtils.isEmpty(value))
+            writer.writeAttribute(attribute, value, null);
+    }
+
+    public void writeStyleClass(ResponseWriter writer, String... styleClasses)
+        throws IOException
+    {
+        // Check if there is only one
+        int i=0;
+        String styleClass = null;
+        for (; i<styleClasses.length; i++) {
+            if (styleClasses[i]!=null) {
+                if (styleClass!=null) {
+                    break; // more than one!
+                }
+                styleClass = styleClasses[i];
+            }
+        }
+        if (i<styleClasses.length)
+            styleClass = StringUtils.arrayToString(styleClasses, 
StringUtils.SPACE, null, true);
+        if (styleClass != null)
+            writer.writeAttribute(InputControl.HTML_ATTR_CLASS, styleClass, 
null);
+    }
+
+    public void writeStyleClass(ResponseWriter writer)
+        throws IOException
+    {
+        String userStyle = 
getTagAttributeStringEx(InputControl.CSS_STYLE_CLASS);
+        writeStyleClass(writer, this.cssStyleClass, userStyle);
+    }
+    
+    public String writeWrapperTag(FacesContext context, boolean renderId, 
boolean renderValue)
+        throws IOException
+    {
+        String wrapperClass = getTagAttributeStringEx("wrapperClass"); 
+        if (wrapperClass==null)
+            return null;
+        // start element
+        String tagName = InputControl.HTML_TAG_DIV;
+        ResponseWriter writer = context.getResponseWriter();
+        writer.startElement(tagName, this.component);
+        // render id
+        if (renderId)
+            writeComponentId(writer);
+        // style class
+        String wrapCtxClass = (renderValue ? "eWrapVal" : "eWrapInp");
+        writeStyleClass(writer, wrapCtxClass, nullIf(wrapperClass, '-'));
+        // return tagName
+        return tagName;
+    }
+    
+    /* ********************** Miscellaneous ********************** */
+
+    protected String nullIf(String value, char nullChar)
+    {
+        return (value==null || value.length()==0 || (value.length()==1 && 
value.charAt(0)==nullChar) ? null : value);   
+    }
     
 }
diff --git 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/FormGridTag.java
 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/FormGridTag.java
index 8066383f..8ba6f9c9 100644
--- 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/FormGridTag.java
+++ 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/FormGridTag.java
@@ -26,7 +26,6 @@ import javax.faces.component.UIOutput;
 import javax.faces.context.FacesContext;
 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.utils.ControlRenderInfo;
@@ -112,7 +111,7 @@ public class FormGridTag extends UIOutput // implements 
NamingContainer
             {   // label facet
                 placeholderFacet.encodeAll(context);
             }
-            else if (renderPlaceholder || 
ObjectUtils.getBoolean(controlTag.getAttributes().get("placeholder"), false))
+            else if (renderPlaceholder || isRenderPlaceholder(controlTag))
             {   // render placeholder   
                 ResponseWriter writer = context.getResponseWriter();
                 String placeholderTag = (CONTROL_TAG!=null ? CONTROL_TAG : 
INPUT_WRAPPER_TAG);
@@ -121,7 +120,8 @@ public class FormGridTag extends UIOutput // implements 
NamingContainer
                 if (CONTROL_TAG!=null && 
TagEncodingHelper.hasComponentId(controlTag))
                     writer.writeAttribute(InputControl.HTML_ATTR_ID, 
controlTag.getClientId(), null);
                 // Style class
-                writer.writeAttribute(InputControl.HTML_ATTR_CLASS, 
TagStyleClass.CONTROL_PLACEHOLDER.get(), null);
+                String controlStyle = 
controlTag.helper.getTagAttributeString(InputControl.CSS_STYLE_CLASS);
+                controlTag.helper.writeStyleClass(writer, 
TagStyleClass.CONTROL_PLACEHOLDER.get(), controlStyle);
                 // Legacy two <td>
                 if (CONTROL_TAG==null && 
InputControl.HTML_TAG_TD.equalsIgnoreCase(placeholderTag))
                     writer.writeAttribute("colspan", 2, null);
@@ -209,8 +209,8 @@ public class FormGridTag extends UIOutput // implements 
NamingContainer
                 log.warn("FormGridTag: Invalid value \"{}\" for attribute 
\"autoControlId\". Allowed values are *|@|&", id);
         }
         // create control info
-        UIComponent placeholderFacet = getFacet("placeholder");
-        boolean renderPlaceholder = (placeholderFacet==null ? 
ObjectUtils.getBoolean(getAttributes().get("placeholder"), false) : false);
+        UIComponent placeholderFacet = 
getFacet(ControlRenderInfo.PLACEHOLDER_ATTRIBUTE);
+        boolean renderPlaceholder = (placeholderFacet==null ? 
ControlRenderInfo.isRenderPlaceholder(this) : false);
         this.controlRenderInfo = new FromGridRenderInfo(mode, 
placeholderFacet, renderPlaceholder, autoControlId);
         return controlRenderInfo;
     }
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 9238c7a4..b8023c4f 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
@@ -116,7 +116,7 @@ public class MenuItemTag extends LinkTag
         helper.writeAttribute(writer, "class", getStyleClass());
 
         // wrap
-        String wrap = (parentMenu!=null ? parentMenu.getItemWrapTag() : null);
+        String wrap = (parentMenu!=null ? parentMenu.getItemWrapperTagName() : 
null);
         if (StringUtils.isNotEmpty(wrap))
         {   // Wrap-Element
             writer.startElement(wrap, this);
@@ -198,18 +198,18 @@ public class MenuItemTag extends LinkTag
     
     protected boolean isCurrent()
     {
-        if (menuId==null || parentMenu==null || 
parentMenu.getCurrentId()==null)
+        if (menuId==null || parentMenu==null || 
parentMenu.getCurrentItemId()==null)
             return false;
         // All present
-        return menuId.equals(parentMenu.getCurrentId());
+        return menuId.equals(parentMenu.getCurrentItemId());
     }
     
     protected boolean isParent()
     {
-        if (menuId==null || parentMenu==null || 
parentMenu.getCurrentId()==null)
+        if (menuId==null || parentMenu==null || 
parentMenu.getCurrentItemId()==null)
             return false;
         // All present
-        String  currentId = parentMenu.getCurrentId();
+        String  currentId = parentMenu.getCurrentItemId();
         return (currentId.length()>menuId.length() && 
currentId.startsWith(menuId));
     }
 
@@ -235,10 +235,10 @@ public class MenuItemTag extends LinkTag
                 return true;
         }
         // Check parent
-        if (menuId==null || parentMenu==null || 
parentMenu.getCurrentId()==null)
+        if (menuId==null || parentMenu==null || 
parentMenu.getCurrentItemId()==null)
             return auto;
         // All present
-        String currentId = parentMenu.getCurrentId();
+        String currentId = parentMenu.getCurrentItemId();
         return currentId.startsWith(menuId+".");
     }
     
@@ -251,7 +251,7 @@ public class MenuItemTag extends LinkTag
             currentOnly = ObjectUtils.getBoolean(value);
         
         // Check parent
-        if (currentOnly && menuId!=null && parentMenu!=null && 
parentMenu.getCurrentId()!=null)
+        if (currentOnly && menuId!=null && parentMenu!=null && 
parentMenu.getCurrentItemId()!=null)
         {    
             return isCurrent() || isParent();
         }
@@ -269,15 +269,15 @@ public class MenuItemTag extends LinkTag
                 styleClass = parentMenu.getItemStyleClass();
             // Menu Class
             if (isCurrent())
-                styleClass = appendStyleClass(styleClass, 
parentMenu.getCurrentClass());
+                styleClass = appendStyleClass(styleClass, 
parentMenu.getCurrentItemClass());
             else if (isParent())
-                styleClass = appendStyleClass(styleClass, 
parentMenu.getParentClass());
+                styleClass = appendStyleClass(styleClass, 
parentMenu.getParentItemClass());
             // expanded
             if (isExpanded())
-                styleClass = appendStyleClass(styleClass, 
parentMenu.getExpandedClass());            
+                styleClass = appendStyleClass(styleClass, 
parentMenu.getItemExpandedClass());            
             // Disabled / enabled
             if (isDisabled())
-                styleClass = appendStyleClass(styleClass, 
parentMenu.getDisabledClass());
+                styleClass = appendStyleClass(styleClass, 
parentMenu.getItemDisabledClass());
         }
         else
         {   // disabled
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 04d08c63..43914247 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
@@ -48,7 +48,6 @@ public class MenuListTag extends UIOutput // implements 
NamingContainer
         expandedClass,
         itemWrapTag,
         defaultItemClass;
-        // autoItemId
     }
     
     protected String currentId = null; 
@@ -58,7 +57,6 @@ public class MenuListTag extends UIOutput // implements 
NamingContainer
     protected String expandedClass = null;
     protected String itemWrapTag = null;
     protected String defaultItemClass = null; // e.g. "level{}"
-    // protected Boolean autoItemId = null;
     protected int level = 0;
     
     private MenuListTag parentMenu = null; 
@@ -144,17 +142,17 @@ public class MenuListTag extends UIOutput // implements 
NamingContainer
         else
         {   // copy from parent
             if (currentId==null)
-                currentId = parentMenu.getCurrentId();
+                currentId = parentMenu.getCurrentItemId();
             if (currentClass==null)
-                currentClass = parentMenu.getCurrentClass();  
+                currentClass = parentMenu.getCurrentItemClass();  
             if (parentClass==null)
-                parentClass = parentMenu.getParentClass();
+                parentClass = parentMenu.getParentItemClass();
             if (disabledClass==null)
-                disabledClass = parentMenu.getDisabledClass();
+                disabledClass = parentMenu.getItemDisabledClass();
             if (expandedClass==null)
-                expandedClass = parentMenu.getExpandedClass();
+                expandedClass = parentMenu.getItemExpandedClass();
             if (itemWrapTag==null)
-                itemWrapTag = parentMenu.getItemWrapTag();
+                itemWrapTag = parentMenu.getItemWrapperTagName();
             if (defaultItemClass==null)
                 defaultItemClass = parentMenu.defaultItemClass;
             // increase level
@@ -162,45 +160,33 @@ public class MenuListTag extends UIOutput // implements 
NamingContainer
         }
     }
     
-    public String getCurrentId()
+    public String getCurrentItemId()
     {
-        if (currentId==null)
-            currentId= 
StringUtils.toString(getStateHelper().get(MenuProperty.currentId));
         return currentId;
     }
 
-    public String getCurrentClass()
+    public String getCurrentItemClass()
     {
-        if (currentClass==null)
-            currentClass= 
StringUtils.toString(getStateHelper().get(MenuProperty.currentClass));
         return currentClass;
     }
 
-    public String getDisabledClass()
+    public String getParentItemClass()
     {
-        if (disabledClass==null)
-            disabledClass= 
StringUtils.toString(getStateHelper().get(MenuProperty.disabledClass));
-        return disabledClass;
+        return parentClass;
     }
 
-    public String getParentClass()
+    public String getItemDisabledClass()
     {
-        if (parentClass==null)
-            parentClass= 
StringUtils.toString(getStateHelper().get(MenuProperty.parentClass));
-        return parentClass;
+        return disabledClass;
     }
 
-    public String getExpandedClass()
+    public String getItemExpandedClass()
     {
-        if (expandedClass==null)
-            expandedClass= 
StringUtils.toString(getStateHelper().get(MenuProperty.expandedClass));
         return expandedClass;
     }
 
-    public String getItemWrapTag()
+    public String getItemWrapperTagName()
     {
-        if (itemWrapTag==null)
-            itemWrapTag= 
StringUtils.toString(getStateHelper().get(MenuProperty.itemWrapTag));
         return itemWrapTag;
     }
     
@@ -226,24 +212,53 @@ public class MenuListTag extends UIOutput // implements 
NamingContainer
         // return default
         return defaultItemClass;
     }
+
+    /* 
+     * Getters and setter with getStateHelper()
+     * Removed with EMPIREDB-441 on 2024-10-12
+     * 
     
-    /*
-    public Boolean isAutoItemId()
+    public String getCurrentItemId()
     {
-        if (this.autoItemId == null) {
-            this.autoItemId = 
(Boolean)getStateHelper().get(Properties.autoItemId);
-            if (this.autoItemId==null) {
-                if (parentMenu==null)
-                    parentMenu = findParentMenu();
-                if (parentMenu!=null)
-                    return parentMenu.isAutoItemId();
-            }
-        }
-        return this.autoItemId;
+        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;
     }
-    */
 
-    /* setters */
+    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()
+    {
+        if (itemWrapTag==null)
+            itemWrapTag= 
StringUtils.toString(getStateHelper().get(MenuProperty.itemWrapTag));
+        return itemWrapTag;
+    }
     
     public void setCurrentId(String currentId)
     {
@@ -286,14 +301,7 @@ public class MenuListTag extends UIOutput // implements 
NamingContainer
         // save
         getStateHelper().put(MenuProperty.itemWrapTag, itemWrapTag);
     }
-
-    /*
-    public void setAutoItemId(Boolean autoItemId)
-    {
-        this.autoItemId = autoItemId;
-        // save
-        getStateHelper().put(Properties.autoItemId, this.autoItemId);
-    }
+    
     */
 
     /*
diff --git 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/TabViewTag.java
 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/TabViewTag.java
index 97189c3a..a457117a 100644
--- 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/TabViewTag.java
+++ 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/TabViewTag.java
@@ -236,7 +236,7 @@ public class TabViewTag extends UIOutput // implements 
NamingContainer
 
         // The Blind
         String showTabBlindJs = null;
-        if 
(ObjectUtils.getBoolean(this.helper.getTagAttributeValue("showBlind")))
+        if (ObjectUtils.getBoolean(helper.getTagAttributeValue("showBlind")))
         {   // hide bar
             String tabBlindClass = TagStyleClass.TAB_BLIND.get();
             writer.startElement(InputControl.HTML_TAG_DIV, this);
@@ -384,7 +384,7 @@ public class TabViewTag extends UIOutput // implements 
NamingContainer
             }
             if (writer!=null)
             {   // encode Tab
-                boolean disabled = 
ObjectUtils.getBoolean(TagEncodingHelper.getTagAttributeValue(page, 
"disabled"));
+                boolean disabled = isPageDisabled(page);
                 writer.startElement(mode.BAR_ITEM_TAG, this);
                 // tab label
                 String styleClasses = TagStyleClass.TAB_LABEL.get();
@@ -491,6 +491,12 @@ public class TabViewTag extends UIOutput // implements 
NamingContainer
     
     protected boolean isPageVisible(TabPageTag page)
     {
-        return 
ObjectUtils.getBoolean(ObjectUtils.coalesce(page.getAttributes().get(this.TAB_RENDERED_ATTRIBUTE),
 true));
+        return 
ObjectUtils.getBoolean(page.getAttributes().get(this.TAB_RENDERED_ATTRIBUTE), 
true);
     }
+    
+    protected boolean isPageDisabled(TabPageTag page)
+    {
+        return ObjectUtils.getBoolean(page.getAttributes().get("disabled"), 
false);
+    }
+    
 }
diff --git 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/ControlRenderInfo.java
 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/ControlRenderInfo.java
index 33c27a54..cc5832f2 100644
--- 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/ControlRenderInfo.java
+++ 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/ControlRenderInfo.java
@@ -20,6 +20,7 @@ package org.apache.empire.jsf2.utils;
 
 import java.io.IOException;
 
+import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.context.ResponseWriter;
 
@@ -37,6 +38,8 @@ public class ControlRenderInfo
      * Use setDefault(ControlRenderInfo renderInfo) in order to change the 
default
      */
     private static ControlRenderInfo DEFAULT_CONTROL_RENDER_INFO = new 
DefaultControlRenderInfo();
+    
+    public static final String PLACEHOLDER_ATTRIBUTE = "placeholder";
 
     public static ControlRenderInfo getDefault()
     {
@@ -48,6 +51,11 @@ public class ControlRenderInfo
         DEFAULT_CONTROL_RENDER_INFO = renderInfo;
     }
     
+    public static boolean isRenderPlaceholder(UIComponent component)
+    {
+        return 
ObjectUtils.getBoolean(component.getAttributes().get(PLACEHOLDER_ATTRIBUTE), 
false);        
+    }
+    
     private static class DefaultControlRenderInfo extends ControlRenderInfo
     {
         public DefaultControlRenderInfo()
@@ -60,7 +68,7 @@ public class ControlRenderInfo
             throws IOException
         {
             // check attribute "placeholder"
-            if 
(ObjectUtils.getBoolean(controlTag.getAttributes().get("placeholder"), false))
+            if (isRenderPlaceholder(controlTag))
             {   // render placeholder for invisible controls 
                 ResponseWriter writer = context.getResponseWriter();
                 writer.startElement(InputControl.HTML_TAG_TD, controlTag);
diff --git 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java
 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java
index 089ad80d..0b3bdf86 100644
--- 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java
+++ 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java
@@ -85,6 +85,10 @@ import org.apache.empire.jsf2.controls.TextInputControl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+/**
+ * TagEncodingHelper
+ * Used by all Empire Components to exchange data and render 
+ */
 public class TagEncodingHelper implements NamingContainer
 {
     public static final String FACES_ID_PREFIX = "j_id";  // Standard Faces ID 
Prefix
@@ -418,7 +422,7 @@ public class TagEncodingHelper implements NamingContainer
         @Override
         public Object getAttributeEx(String name)
         {
-            return getAttributeValueEx(name);
+            return getTagAttributeValueEx(name);
         }
     }
 
@@ -812,14 +816,13 @@ public class TagEncodingHelper implements NamingContainer
             if (evalExpression)
                 return component.getValue();
             else
-            {   // return value or value expression
+            {   // Check LocalValue and ValueExpression
                 Object value = component.getLocalValue();
                 if (value!=null && (component instanceof UIInput) && 
!((UIInput)component).isLocalValueSet())
                     value= null; /* should never come here! */
                 if (value==null)
-                    value = findValueExpression("value", false);
-                
-                // value = tag.getValue();
+                    value = findValueExpression("value");
+                // Return the local value or the ValueExpression if any
                 return value;
             }
         }
@@ -1030,7 +1033,7 @@ public class TagEncodingHelper implements NamingContainer
             return DisabledType.READONLY;
         }
         // Check attribute
-        Object dis = getAttributeValueEx("disabled");
+        Object dis = getTagAttributeValueEx("disabled");
         if (ObjectUtils.isEmpty(dis))
             return null; // not provided!
         // direct
@@ -1220,7 +1223,7 @@ public class TagEncodingHelper implements NamingContainer
         // Find expression
         if (this.hasValueExpr<0)
         {   // Find expression
-            ValueExpression ve = findValueExpression("value", false);
+            ValueExpression ve = findValueExpression("value");
             if (ve != null)
             {   // We have a ValueExpression!
                 // Now unwrap for Facelet-Tags to work
@@ -1239,17 +1242,18 @@ public class TagEncodingHelper implements 
NamingContainer
         }
         return (hasValueExpr>0);
     }
-        
+    
+    // composite component expression
     protected static final String CC_ATTR_EXPR = "#{cc.attrs.";
     
     @SuppressWarnings("unchecked")
-    protected ValueExpression findValueExpression(String attribute, boolean 
allowLiteral)
+    protected ValueExpression findValueExpression(String attribute)
     {
         // Check for expression
         ValueExpression ve = component.getValueExpression(attribute);
         if (ve == null)
             return null;
-        // Find expression
+        // Check for composite component expression
         UIComponent parent = component;
         String expr = ve.getExpressionString();
         while (expr.startsWith(CC_ATTR_EXPR))
@@ -1277,9 +1281,10 @@ public class TagEncodingHelper implements NamingContainer
             // find attribute
             ValueExpression next = parent.getValueExpression(attrib);
             if (next == null)
-            {   // allow literal
+            {   /* allow literal (obsolte 2024-10-12)
                 if (allowLiteral && (parent.getAttributes().get(attrib)!=null))
                     return ve;
+                */    
                 // not found
                 return null;
             }
@@ -1290,34 +1295,6 @@ public class TagEncodingHelper implements NamingContainer
         // found
         return ve;
     }
-    
-    protected final Options getValueOptions()
-    {
-        if (this.optionsDetected==false)
-        {   // detect Options
-            this.options = detectValueOptions();
-            this.optionsDetected = true;
-        }
-        return this.options;
-    }
-    
-    protected Options detectValueOptions()
-    {
-        // null value
-        Object attr = getTagAttributeValue("options");
-        if (attr != null && (attr instanceof Options))
-            return ((Options) attr);
-        if (hasColumn())
-        {   // Do we have a record?
-            Object rec = (this.record!=null ? this.record : findRecord());
-            if ((rec instanceof Record) && ((Record)rec).isValid()) 
-                return ((Record)rec).getFieldOptions(unwrapColumn(column));
-            // get From Column
-            return column.getOptions();
-        }
-        // not available
-        return null;
-    }
 
     protected Object getBeanPropertyValue(Object bean, String property)
     {
@@ -1383,6 +1360,34 @@ public class TagEncodingHelper implements NamingContainer
         }
     }
     
+    protected final Options getValueOptions()
+    {
+        if (this.optionsDetected==false)
+        {   // detect Options
+            this.options = detectValueOptions();
+            this.optionsDetected = true;
+        }
+        return this.options;
+    }
+    
+    protected Options detectValueOptions()
+    {
+        // null value
+        Object attr = getTagAttributeValue("options");
+        if (attr != null && (attr instanceof Options))
+            return ((Options) attr);
+        if (hasColumn())
+        {   // Do we have a record?
+            Object rec = (this.record!=null ? this.record : findRecord());
+            if ((rec instanceof Record) && ((Record)rec).isValid()) 
+                return ((Record)rec).getFieldOptions(unwrapColumn(column));
+            // get From Column
+            return column.getOptions();
+        }
+        // not available
+        return null;
+    }
+    
     public String getValueTooltip(Object value)
     {
         if (value == null)
@@ -1475,6 +1480,8 @@ public class TagEncodingHelper implements NamingContainer
         return textResolver;
     }
     
+    /* ********************** Error messages ********************** */
+    
     protected boolean detectError(FacesContext context)
     {
         Iterator<FacesMessage> iter = 
context.getMessages(component.getClientId());
@@ -1501,175 +1508,6 @@ public class TagEncodingHelper implements 
NamingContainer
         FacesMessage msg = getFieldValueErrorMessage(context, e, value);
         context.addMessage(component.getClientId(), msg);
     }
-
-    public Object getAttributeValueEx(String name)
-    { 
-        Object value = getTagAttributeValue(name);
-        if (value==null && hasColumn())
-        {   // Check Column
-            value = column.getAttribute(name);
-        }
-        // Checks whether it's another column    
-        if (value instanceof Column)
-        {   // Special case: Value is a column
-            Column col = ((Column)value);
-            Object rec = getRecord();
-            if (rec instanceof Record)
-                return ((Record)rec).get(col);
-            else if (rec!=null)
-            {   // Get Value from a bean
-                String property = col.getBeanPropertyName();
-                try
-                {   // Use Beanutils to get Property
-                    PropertyUtilsBean pub = 
BeanUtilsBean.getInstance().getPropertyUtils();
-                    return pub.getSimpleProperty(rec, property);
-                }
-                catch (Exception e)
-                {   log.error("BeanUtils.getSimpleProperty failed for 
"+property, e);
-                    return null;
-                }
-            }    
-            return null;
-        }
-        return value;
-    }
-
-    public String getTagAttributeStringEx(String name)
-    {
-        Object value = getAttributeValueEx(name);
-        return (value!=null) ? StringUtils.nullIfEmpty(value) : null;
-    }
-    
-    public Object getTagAttributeValue(String name)
-    {
-        return TagEncodingHelper.getTagAttributeValue(component, name);
-    }
-    
-    public boolean hasComponentId()
-    {
-        return hasComponentId(this.component);        
-    }
-    
-    public static boolean hasComponentId(UIComponent component)
-    {
-        String id = component.getId();
-        return (id!=null && id.length()>0 && !id.startsWith(FACES_ID_PREFIX)); 
       
-    }
-
-    public static Object getTagAttributeValue(UIComponent comp, String name)
-    {
-        Object value = comp.getAttributes().get(name);
-        if (value==null)
-        {   // try value expression
-            ValueExpression ve = comp.getValueExpression(name);
-            if (ve!=null)
-            {   // It's a value expression
-                FacesContext ctx = FacesContext.getCurrentInstance();
-                value = ve.getValue(ctx.getELContext());
-            }
-        }
-        return value;
-    }
-
-    public static String buildComponentId(String s)
-    {
-        if (s==null || s.length()==0)
-            return null;
-        StringBuilder b = new StringBuilder(s.length());
-        for (int i=0; i<s.length(); i++)
-        {
-            char c = s.charAt(i);
-            if (c!='_' && !StringUtils.isCharBetween(c, 'A', 'Z') && 
!StringUtils.isCharBetween(c, 'a', 'z') && !StringUtils.isNumber(c))
-                c='-';
-            b.append(c);
-        }
-        return b.toString();
-    }
-    
-    public String getTagAttributeString(String name, String defValue)
-    {
-        Object value = getTagAttributeValue(name);
-        String sval = StringUtils.nullIfEmpty(value);
-        return (defValue!=null ? StringUtils.coalesce(sval, defValue) : sval);
-    }
-
-    public String getTagAttributeString(String name)
-    {
-        return getTagAttributeString(name, null);
-    }
-
-    public void writeAttribute(ResponseWriter writer, String attribute, Object 
value)
-        throws IOException
-    {
-        if (value != null)
-            writer.writeAttribute(attribute, value, null);
-    }
-    
-    public void writeComponentId(ResponseWriter writer, boolean renderAutoId)
-        throws IOException
-    {
-        // render id
-        if (renderAutoId || hasComponentId())
-            writer.writeAttribute(InputControl.HTML_ATTR_ID, 
component.getClientId(), null);
-    }
-    
-    public void writeComponentId(ResponseWriter writer)
-            throws IOException
-    {
-        writeComponentId(writer, (component instanceof NamingContainer));
-    }
-
-    public void writeStyleClass(ResponseWriter writer, String... styleClasses)
-        throws IOException
-    {
-        // Check if there is only one
-        int i=0;
-        String styleClass = null;
-        for (; i<styleClasses.length; i++) {
-            if (styleClasses[i]!=null) {
-                if (styleClass!=null) {
-                    break; // more than one!
-                }
-                styleClass = styleClasses[i];
-            }
-        }
-        if (i<styleClasses.length)
-            styleClass = StringUtils.arrayToString(styleClasses, 
StringUtils.SPACE, null, true);
-        if (styleClass != null)
-            writer.writeAttribute(InputControl.HTML_ATTR_CLASS, styleClass, 
null);
-    }
-
-    public void writeStyleClass(ResponseWriter writer)
-        throws IOException
-    {
-        String userStyle = 
getTagAttributeStringEx(InputControl.CSS_STYLE_CLASS);
-        writeStyleClass(writer, this.cssStyleClass, userStyle);
-    }
-    
-    public String writeWrapperTag(FacesContext context, boolean renderId, 
boolean renderValue)
-        throws IOException
-    {
-        String wrapperClass = getTagAttributeStringEx("wrapperClass"); 
-        if (wrapperClass==null)
-            return null;
-        // start element
-        String tagName = InputControl.HTML_TAG_DIV;
-        ResponseWriter writer = context.getResponseWriter();
-        writer.startElement(tagName, this.component);
-        // render id
-        if (renderId)
-            writeComponentId(writer);
-        // style class
-        String wrapCtxClass = (renderValue ? "eWrapVal" : "eWrapInp");
-        writeStyleClass(writer, wrapCtxClass, nullIf(wrapperClass, '-'));
-        // return tagName
-        return tagName;
-    }
-
-    protected String nullIf(String value, char nullChar)
-    {
-        return (value==null || value.length()==0 || (value.length()==1 && 
value.charAt(0)==nullChar) ? null : value);   
-    }
     
     /* ********************** FormGridTag ********************** */
 
@@ -1696,7 +1534,7 @@ public class TagEncodingHelper implements NamingContainer
         return (formGrid!=null) ? formGrid.getControlRenderInfo() : null;  
     }
 
-    /* ********************** label ********************** */
+    /* ********************** Label ********************** */
 
     protected String getLabelValue(Column column, boolean colon)
     {
@@ -1749,7 +1587,7 @@ public class TagEncodingHelper implements NamingContainer
             {   // for LabelTag
                 forInput = this.getColumnName();
                 // readOnly
-                Object val = getAttributeValueEx("readOnly");
+                Object val = getTagAttributeValueEx("readOnly");
                 if (val!=null)
                     this.readOnly = (ObjectUtils.getBoolean(val) ? (byte)1 : 
(byte)0);
             }
@@ -1820,7 +1658,7 @@ public class TagEncodingHelper implements NamingContainer
             }
             else if (component instanceof LabelTag)
             {   // update readOnly
-                Object val = getAttributeValueEx("readOnly");
+                Object val = getTagAttributeValueEx("readOnly");
                 if (val!=null)
                     this.readOnly = (ObjectUtils.getBoolean(val) ? (byte)1 : 
(byte)0);
             }
@@ -1981,14 +1819,7 @@ public class TagEncodingHelper implements NamingContainer
         return null;
     }
 
-    public final boolean isInsideUIData()
-    {
-        if (component==null)
-            return false;
-        if (this.insideUIData<0)
-            this.insideUIData=(detectInsideUIData() ? (byte)1 : (byte)0);
-        return (this.insideUIData>0);
-    }
+    /* ********************** UIData detection ********************** */
     
     protected boolean detectInsideUIData()
     {
@@ -2008,6 +1839,43 @@ public class TagEncodingHelper implements NamingContainer
         }
         return false;
     }
+
+    public final boolean isInsideUIData()
+    {
+        if (component==null)
+            return false;
+        if (this.insideUIData<0)
+            this.insideUIData=(detectInsideUIData() ? (byte)1 : (byte)0);
+        return (this.insideUIData>0);
+    }
+    
+    /* ********************** Component id ********************** */
+
+    public static String buildComponentId(String s)
+    {
+        if (s==null || s.length()==0)
+            return null;
+        StringBuilder b = new StringBuilder(s.length());
+        for (int i=0; i<s.length(); i++)
+        {
+            char c = s.charAt(i);
+            if (c!='_' && !StringUtils.isCharBetween(c, 'A', 'Z') && 
!StringUtils.isCharBetween(c, 'a', 'z') && !StringUtils.isNumber(c))
+                c='-';
+            b.append(c);
+        }
+        return b.toString();
+    }
+    
+    public static boolean hasComponentId(UIComponent component)
+    {
+        String id = component.getId();
+        return (id!=null && id.length()>0 && !id.startsWith(FACES_ID_PREFIX)); 
       
+    }
+
+    public boolean hasComponentId()
+    {
+        return hasComponentId(this.component);        
+    }
     
     public void saveComponentId(UIComponent comp)
     {
@@ -2044,5 +1912,154 @@ public class TagEncodingHelper implements 
NamingContainer
             comp.setId(resetId);
         }
     }
+
+    /* ********************** Attribute value ********************** */
+    
+    public Object getTagAttributeValue(String name)
+    {
+        Object value = component.getAttributes().get(name);
+        /*
+         * Removed with EMPIREDB-441 on 2024-10-12
+         * ValueExpression expression is already checked internally by 
getAttributes()
+         * 
+        if (value==null)
+        {   // try value expression
+            ValueExpression ve = component.getValueExpression(name);
+            if (ve!=null)
+            {   // It's a value expression
+                FacesContext ctx = FacesContext.getCurrentInstance();
+                value = ve.getValue(ctx.getELContext());
+            }
+        }
+        */
+        return value;
+    }
+    
+    public String getTagAttributeString(String name, String defValue)
+    {
+        Object value = getTagAttributeValue(name);
+        String sval  = StringUtils.nullIfEmpty(value);
+        return (sval==null ? defValue : sval);
+    }
+
+    public String getTagAttributeString(String name)
+    {
+        return getTagAttributeString(name, null);
+    }
+
+    public Object getTagAttributeValueEx(String name)
+    { 
+        Object value = getTagAttributeValue(name);
+        if (value==null && hasColumn())
+        {   // Check Column
+            value = column.getAttribute(name);
+        }
+        // Checks whether it's another column    
+        if (value instanceof Column)
+        {   // Special case: Value is a column
+            Column col = ((Column)value);
+            Object rec = getRecord();
+            if (rec instanceof Record)
+                return ((Record)rec).get(col);
+            else if (rec!=null)
+            {   // Get Value from a bean
+                String property = col.getBeanPropertyName();
+                try
+                {   // Use Beanutils to get Property
+                    PropertyUtilsBean pub = 
BeanUtilsBean.getInstance().getPropertyUtils();
+                    return pub.getSimpleProperty(rec, property);
+                }
+                catch (Exception e)
+                {   log.error("BeanUtils.getSimpleProperty failed for 
"+property, e);
+                    return null;
+                }
+            }    
+            return null;
+        }
+        return value;
+    }
+
+    public String getTagAttributeStringEx(String name)
+    {
+        Object value = getTagAttributeValueEx(name);
+        return (value!=null) ? StringUtils.nullIfEmpty(value) : null;
+    }
+    
+    /* ********************** Response write helper ********************** */
+    
+    public void writeComponentId(ResponseWriter writer, boolean renderAutoId)
+        throws IOException
+    {
+        // render id
+        if (renderAutoId || hasComponentId())
+            writer.writeAttribute(InputControl.HTML_ATTR_ID, 
component.getClientId(), null);
+    }
+    
+    public void writeComponentId(ResponseWriter writer)
+        throws IOException
+    {
+        writeComponentId(writer, (component instanceof NamingContainer));
+    }
+
+    public void writeAttribute(ResponseWriter writer, String attribute, Object 
value)
+        throws IOException
+    {
+        if (value != null && !ObjectUtils.isEmpty(value))
+            writer.writeAttribute(attribute, value, null);
+    }
+
+    public void writeStyleClass(ResponseWriter writer, String... styleClasses)
+        throws IOException
+    {
+        // Check if there is only one
+        int i=0;
+        String styleClass = null;
+        for (; i<styleClasses.length; i++) {
+            if (styleClasses[i]!=null) {
+                if (styleClass!=null) {
+                    break; // more than one!
+                }
+                styleClass = styleClasses[i];
+            }
+        }
+        if (i<styleClasses.length)
+            styleClass = StringUtils.arrayToString(styleClasses, 
StringUtils.SPACE, null, true);
+        if (styleClass != null)
+            writer.writeAttribute(InputControl.HTML_ATTR_CLASS, styleClass, 
null);
+    }
+
+    public void writeStyleClass(ResponseWriter writer)
+        throws IOException
+    {
+        String userStyle = 
getTagAttributeStringEx(InputControl.CSS_STYLE_CLASS);
+        writeStyleClass(writer, this.cssStyleClass, userStyle);
+    }
+    
+    public String writeWrapperTag(FacesContext context, boolean renderId, 
boolean renderValue)
+        throws IOException
+    {
+        String wrapperClass = getTagAttributeStringEx("wrapperClass"); 
+        if (wrapperClass==null)
+            return null;
+        // start element
+        String tagName = InputControl.HTML_TAG_DIV;
+        ResponseWriter writer = context.getResponseWriter();
+        writer.startElement(tagName, this.component);
+        // render id
+        if (renderId)
+            writeComponentId(writer);
+        // style class
+        String wrapCtxClass = (renderValue ? "eWrapVal" : "eWrapInp");
+        writeStyleClass(writer, wrapCtxClass, nullIf(wrapperClass, '-'));
+        // return tagName
+        return tagName;
+    }
+    
+    /* ********************** Miscellaneous ********************** */
+
+    protected String nullIf(String value, char nullChar)
+    {
+        return (value==null || value.length()==0 || (value.length()==1 && 
value.charAt(0)==nullChar) ? null : value);   
+    }
     
 }
diff --git a/empire-db/src/main/java/org/apache/empire/commons/StringUtils.java 
b/empire-db/src/main/java/org/apache/empire/commons/StringUtils.java
index df147532..6d7e13d2 100644
--- a/empire-db/src/main/java/org/apache/empire/commons/StringUtils.java
+++ b/empire-db/src/main/java/org/apache/empire/commons/StringUtils.java
@@ -161,7 +161,7 @@ public class StringUtils
         if (value==null)
             return null;
         String strval = value.toString();
-        return ((strval.length()==0) ? null : strval);   
+        return (isEmpty(strval) ? null : strval);   
     }
 
     /**
@@ -497,7 +497,7 @@ public class StringUtils
     public static boolean isEmpty(String s)
     {
         if (s!=null)
-        {   // find non-space character
+        {   // check for any non-space character
             for (int i=0; i<s.length(); i++)
                 if (s.charAt(i)>' ')
                     return false;


Reply via email to