EMPIREDB-235
Allow to attach client behaviors to input control components
diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/custom/controls/FileInputControl.java b/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/custom/controls/FileInputControl.java
index b062dcf..2b42e80 100644
--- a/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/custom/controls/FileInputControl.java
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/custom/controls/FileInputControl.java
@@ -30,7 +30,7 @@
 

 public class FileInputControl extends InputControl

 {

-    public static final String             NAME                = "blob";

+    public static final String NAME = "file";

 

     private Class<? extends HtmlInputFile> inputComponentClass = null;

 

@@ -52,6 +52,7 @@
         try

         {

             input = inputComponentClass.newInstance();

+            copyAttributes(parent, ii, input);

         }

         catch (InstantiationException e1)

         {

@@ -61,16 +62,13 @@
         {

             throw new InternalException(e2);

         }

-

-        copyAttributes(parent, ii, input);

-        setInputValue(input, ii);

-        input.setDisabled(ii.isDisabled());

-        

         compList.add(input);

+        // update

+        updateInputState(compList, ii, context, true);

     }

 

     @Override

-    protected void updateInputState(List<UIComponent> compList, InputInfo ii, FacesContext context)

+    protected void updateInputState(List<UIComponent> compList, InputInfo ii, FacesContext context, boolean setValue)

     {

         UIComponent comp = compList.get(0);

         if (!(comp instanceof HtmlInputFile))

@@ -80,6 +78,9 @@
         // update state

         HtmlInputFile input = (HtmlInputFile) comp;

         input.setDisabled(ii.isDisabled());

+        // set value

+        if (setValue)

+            setInputValue(input, ii);

     }

 

     public class HtmlInputFile extends HtmlInputText

diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/ControlTag.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/ControlTag.java
index 1139804..0bce482 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/ControlTag.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/ControlTag.java
@@ -19,6 +19,7 @@
 package org.apache.empire.jsf2.components;

 

 import java.io.IOException;

+import java.util.List;

 

 import javax.faces.component.NamingContainer;

 import javax.faces.component.UIComponent;

@@ -425,7 +426,8 @@
                     this.control = helper.getInputControl();

                 if (this.inpInfo==null)

                     this.inpInfo = helper.getInputInfo(context);

-                this.control.updateInputState(parent, inpInfo, context);

+                // update state

+                this.control.updateInputState(parent, inpInfo, context, false);

             }

         }

         // default

@@ -484,7 +486,7 @@
      * @param parent the InputSeparatorComponent

      * @throws IOException

      */

-    protected void encodeInput(FacesContext context, UIComponentBase parent)

+    protected void encodeInput(FacesContext context, UIComponent parent)

         throws IOException

     {

         // render components

@@ -492,6 +494,8 @@
             creatingComponents = true;

             // check children

             int count = parent.getChildCount();

+            UIComponent valueComp = (count>0 ? parent.getChildren().get(count-1) : null);

+            boolean resetChildId = (count==0);

             // continue

             this.inpInfo = helper.getInputInfo(context);

             // set required

@@ -499,18 +503,33 @@
                 super.setRequired(helper.isValueRequired());

 	        // create Input Controls

             // boolean recordReadOnly = helper.isRecordReadOnly();

-            boolean readOnly = helper.isRecordReadOnly();

-            control.renderInput(parent, inpInfo, context, !readOnly);

-            // create Value Component

-            UIComponent valueComp = (count>0 ? parent.getChildren().get(count-1) : null);

-            if (valueComp == null)

-            {   // create ValueOutputComponent

-                valueComp = new ValueOutputComponent();

-                parent.getChildren().add(valueComp);

-                valueComp.setRendered(readOnly);

-                if (readOnly)

-                    valueComp.encodeAll(context);

+            if (count==0)

+            {   // Create components

+                control.createInput(parent, inpInfo, context);

+                // create Value Component

+                if (valueComp == null)

+                {   // create ValueOutputComponent

+                    valueComp = new ValueOutputComponent();

+                    parent.getChildren().add(valueComp);

+                }

             }

+            else

+            {   // Update

+                control.updateInputState(parent, inpInfo, context, true);

+            }

+            // set rendered

+            boolean readOnly = helper.isRecordReadOnly();

+            List<UIComponent> children = parent.getChildren();

+            for (UIComponent child : children)

+            {   // reset child id

+                if (resetChildId && child.getId()!=null)

+                    child.setId(child.getId());

+                // set rendered

+                boolean valueOutput = (child instanceof ValueOutputComponent);

+                child.setRendered((valueOutput ? readOnly : !readOnly));

+            }

+            // render

+            control.renderInput(parent, inpInfo, context);

             // render

         } finally {

             creatingComponents = false;

@@ -649,6 +668,5 @@
             return true;

         // partial  

         return helper.isPartialSubmit(context);

-    }

-    

+    }    

 }

diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/InputTag.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/InputTag.java
index 9bfcdc8..1441a88 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/InputTag.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/InputTag.java
@@ -19,15 +19,18 @@
 package org.apache.empire.jsf2.components;

 

 import java.io.IOException;

+import java.util.List;

 import java.util.Map;

 

 import javax.faces.component.NamingContainer;

+import javax.faces.component.UIComponent;

 import javax.faces.component.UIInput;

 import javax.faces.component.visit.VisitCallback;

 import javax.faces.component.visit.VisitContext;

 import javax.faces.context.FacesContext;

 import javax.faces.context.ResponseWriter;

 import javax.faces.convert.ConverterException;

+import javax.faces.view.AttachedObjectHandler;

 

 import org.apache.empire.data.Column;

 import org.apache.empire.db.exceptions.FieldIllegalValueException;

@@ -161,8 +164,18 @@
             // set required

             if (hasRequiredFlagSet == false)

                 super.setRequired(helper.isValueRequired());

+            // create input

+            if (this.getChildCount()==0)

+            {   // create input

+                control.createInput(this, inpInfo, context);

+                attachEvents(context);

+            }

+            else

+            {   // update state

+                control.updateInputState(this, inpInfo, context, true);

+            }

             // render input

-            control.renderInput(this, inpInfo, context, true);

+            control.renderInput(this, inpInfo, context);

         }

         saveState();

     }

@@ -350,4 +363,34 @@
         helper.writeAttribute(writer, "title", helper.getValueTooltip(title));

         return tagName;

     }

+    

+    protected void attachEvents(FacesContext context)

+    {

+        // Events available?

+        @SuppressWarnings("unchecked")

+        List<AttachedObjectHandler> result = (List<AttachedObjectHandler>) getAttributes().get("javax.faces.RetargetableHandlers");

+        if (result == null)

+        {

+            return;

+        }

+        UIInput inputComponent = null;

+        for (UIComponent c : getChildren())

+        {

+            if (c instanceof UIInput)

+            {   // found

+                inputComponent = (UIInput)c;

+                break;

+            }

+        }

+        if (inputComponent == null)

+            return;

+        // Attach Events

+        for (AttachedObjectHandler aoh : result)

+        {

+            aoh.applyAttachedObject(context, inputComponent);

+        }

+        // remove

+        result.clear();

+        getAttributes().remove("javax.faces.RetargetableHandlers");

+    }

 }

diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/SelectTag.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/SelectTag.java
index d4a0c9e..91a18c8 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/SelectTag.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/SelectTag.java
@@ -19,7 +19,6 @@
 package org.apache.empire.jsf2.components;

 

 import java.io.IOException;

-import java.util.List;

 import java.util.Map;

 

 import javax.faces.component.NamingContainer;

@@ -28,13 +27,13 @@
 import javax.faces.component.visit.VisitCallback;

 import javax.faces.component.visit.VisitContext;

 import javax.faces.context.FacesContext;

-import javax.faces.view.AttachedObjectHandler;

 

 import org.apache.empire.commons.ObjectUtils;

 import org.apache.empire.commons.Options;

 import org.apache.empire.commons.StringUtils;

 import org.apache.empire.jsf2.app.FacesUtils;

 import org.apache.empire.jsf2.app.TextResolver;

+import org.apache.empire.jsf2.controls.InputAttachedObjectsHandler;

 import org.apache.empire.jsf2.controls.InputControlManager;

 import org.apache.empire.jsf2.controls.SelectInputControl;

 import org.apache.empire.jsf2.utils.TagEncodingHelper;

@@ -119,8 +118,8 @@
         {

             inputComponent = createSelectOneMenu(textResolver);

             this.getChildren().add(0, inputComponent);

-            // attach events

-            attachEvents(context, inputComponent);

+            // attach objects

+            addAttachedObjects(context, inputComponent);

         }

         // render components

         inputComponent.encodeAll(context);

@@ -268,23 +267,11 @@
             input.setOnchange(StringUtils.toString(value));

         }

     }

-

-    protected void attachEvents(FacesContext context, UIInput inputComponent)

+    

+    protected void addAttachedObjects(FacesContext context, UIInput inputComponent)

     {

-        // Events available?

-        @SuppressWarnings("unchecked")

-        List<AttachedObjectHandler> result = (List<AttachedObjectHandler>) getAttributes().get("javax.faces.RetargetableHandlers");

-        if (result == null)

-        {

-            return;

-        }

-        // Attach Events

-        for (AttachedObjectHandler aoh : result)

-        {

-            aoh.applyAttachedObject(context, inputComponent);

-        }

-        // remove

-        result.clear();

-        getAttributes().remove("javax.faces.RetargetableHandlers");

+        InputAttachedObjectsHandler aoh = InputControlManager.getAttachedObjectsHandler();

+        if (aoh!=null)

+            aoh.addAttachedObjects(this, context, null, inputComponent);

     }

 }

diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/CheckboxInputControl.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/CheckboxInputControl.java
index 4345ac1..177ae32 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/CheckboxInputControl.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/CheckboxInputControl.java
@@ -27,6 +27,7 @@
 import javax.faces.context.ResponseWriter;

 

 import org.apache.empire.commons.ObjectUtils;

+import org.apache.empire.exceptions.InvalidArgumentException;

 import org.apache.empire.exceptions.UnexpectedReturnValueException;

 

 public class CheckboxInputControl extends InputControl

@@ -60,37 +61,20 @@
     @Override

     protected void createInputComponents(UIComponent parent, InputInfo ii, FacesContext context, List<UIComponent> compList)

     {

-        HtmlSelectBooleanCheckbox input;

-        if (compList.size() == 0)

-        { // create component

-            input = InputControlManager.createComponent(context, this.inputComponentClass);

-            // copy attributes

-            copyAttributes(parent, ii, input);

-            // add

-            compList.add(input);

-        }

-        else

-        { // check type

-            UIComponent comp = compList.get(0);

-            if (!(comp instanceof HtmlSelectBooleanCheckbox))

-                throw new UnexpectedReturnValueException(comp.getClass().getName(), "compList.get");

-            // cast

-            input = (HtmlSelectBooleanCheckbox) comp;

-        }

-

-        // disabled

-        boolean disabled = ii.isDisabled();

-        input.setDisabled(disabled);

-

-        // style

-        addRemoveDisabledStyle(input, input.isDisabled());

-

-        // Set Value

-        setInputValue(input, ii);

+        if (!compList.isEmpty())

+            throw new InvalidArgumentException("compList", compList);

+        // create

+        HtmlSelectBooleanCheckbox input = InputControlManager.createComponent(context, this.inputComponentClass);

+        // copy attributes

+        copyAttributes(parent, ii, input);

+        // add

+        compList.add(input);

+        // set style and value

+        updateInputState(compList, ii, context, true);

     }

 

     @Override

-    protected void updateInputState(List<UIComponent> compList, InputInfo ii, FacesContext context)

+    protected void updateInputState(List<UIComponent> compList, InputInfo ii, FacesContext context, boolean setValue)

     {

         UIComponent comp = compList.get(0);

         if (!(comp instanceof HtmlSelectBooleanCheckbox))

@@ -103,6 +87,9 @@
         input.setDisabled(disabled);

         // style

         addRemoveDisabledStyle(input, input.isDisabled());

+        // set value

+        if (setValue)

+            setInputValue(input, ii);

     }

 

     @Override

diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputAttachedObjectsHandler.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputAttachedObjectsHandler.java
new file mode 100644
index 0000000..41975aa
--- /dev/null
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputAttachedObjectsHandler.java
@@ -0,0 +1,91 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ *

+ *  http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+package org.apache.empire.jsf2.controls;

+

+import java.util.List;

+

+import javax.el.ValueExpression;

+import javax.faces.component.UIComponent;

+import javax.faces.component.UIComponentBase;

+import javax.faces.context.FacesContext;

+import javax.faces.view.AttachedObjectHandler;

+

+import org.apache.empire.commons.StringUtils;

+import org.apache.empire.data.Column;

+import org.slf4j.Logger;

+import org.slf4j.LoggerFactory;

+

+public class InputAttachedObjectsHandler

+{

+    private static final Logger log = LoggerFactory.getLogger(InputAttachedObjectsHandler.class);

+    

+    /**

+     * Allows to add objects such as events, validators, etc to the dynamically created input components 

+     * @param parent the CompositeComponent parent

+     * @param context the faces context

+     * @param column the column for which to attach the objects (optional, i.e. may be null) 

+     * @param inputComponent the input component created by the InputControl implementation

+     */

+    public void addAttachedObjects(UIComponent parent, FacesContext context, Column column, UIComponentBase inputComponent)

+    {

+        // Move RetargetableHandlers 

+        @SuppressWarnings("unchecked")

+        List<AttachedObjectHandler> result = (List<AttachedObjectHandler>) parent.getAttributes().get("javax.faces.RetargetableHandlers");

+        if (result == null)

+        {

+            return;

+        }

+        // Attach Events

+        for (AttachedObjectHandler aoh : result)

+        {

+            log.info("applying RetargetableHandlers to component {}", inputComponent.getId());

+            aoh.applyAttachedObject(context, inputComponent);

+        }

+        // remove

+        result.clear();

+        parent.getAttributes().remove("javax.faces.RetargetableHandlers");

+    }

+

+    /**

+     * helper to get a tag attribute value

+     * @param component the CompositeComponent parent 

+     * @param name the name of the attribute

+     * @return the value of the attribute

+     */

+    protected Object getTagAttributeValue(UIComponent component, String name)

+    {

+        Object value = component.getAttributes().get(name);

+        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;

+    }

+    

+    protected final String getTagAttributeValueString(UIComponent component, String name)

+    {

+        return StringUtils.toString(getTagAttributeValue(component, name));

+    }

+    

+}

diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControl.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControl.java
index bbeccdc..051b777 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControl.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControl.java
@@ -25,6 +25,7 @@
 

 import javax.el.ValueExpression;

 import javax.faces.component.UIComponent;

+import javax.faces.component.UIComponentBase;

 import javax.faces.component.UIData;

 import javax.faces.component.UIInput;

 import javax.faces.context.FacesContext;

@@ -35,9 +36,9 @@
 import org.apache.empire.commons.StringUtils;

 import org.apache.empire.data.Column;

 import org.apache.empire.exceptions.InvalidArgumentException;

+import org.apache.empire.exceptions.ItemNotFoundException;

 import org.apache.empire.exceptions.UnexpectedReturnValueException;

 import org.apache.empire.jsf2.app.TextResolver;

-import org.apache.empire.jsf2.components.ControlTag.ValueOutputComponent;

 import org.slf4j.Logger;

 import org.slf4j.LoggerFactory;

 

@@ -171,6 +172,29 @@
         return this.creatingComponents;

     }

     

+    /* createInput */ 

+    public void createInput(UIComponent comp, InputInfo ii, FacesContext context)

+    {   // createInputComponents

+        List<UIComponent> children = comp.getChildren();

+        try {

+            this.creatingComponents = true;

+            createInputComponents(comp, ii, context, children);

+            // add attached objects

+            UIComponent parent = comp;

+            while (!(parent instanceof UIInput))

+                parent = parent.getParent();

+            for (UIComponent child : children)

+            {   // check type

+                if (!(child instanceof UIComponentBase))

+                    continue;

+                // add attached objects

+                addAttachedObjects(parent, context, ii, ((UIComponentBase)child));

+            }

+        } finally {

+            this.creatingComponents = false;

+        }

+    }

+    

     /* Value */

     public void renderValue(ValueInfo vi, ResponseWriter writer)

         throws IOException

@@ -180,38 +204,24 @@
     }

 

     /* renderInput */ 

-    public void renderInput(UIComponent comp, InputInfo ii, FacesContext context, boolean rendered)

+    public void renderInput(UIComponent comp, InputInfo ii, FacesContext context)

         throws IOException

     {

-        boolean resetChildId = comp.getChildren().isEmpty();

-        // createInputComponents

-        try {

-            this.creatingComponents = true;

-            createInputComponents(comp, ii, context, comp.getChildren());

-        } finally {

-            this.creatingComponents = false;

-        }

         // Encode all

         for (UIComponent child : comp.getChildren())

         {   // reset child-id

-            // necessary only inside UIData

-            if (resetChildId && child.getId()!=null)

-                child.setId(child.getId());

-            // set rendered

-            boolean valueOutput = (child instanceof ValueOutputComponent);

-            child.setRendered((valueOutput ? !rendered : rendered));

             // render

             if (child.isRendered())

                 child.encodeAll(context);

         }

     }

     

-    public void updateInputState(UIComponent parent, InputInfo ii, FacesContext context)

+    public void updateInputState(UIComponent parent, InputInfo ii, FacesContext context, boolean setValue)

     {

         List<UIComponent> cl = parent.getChildren(); 

         if (cl.isEmpty())

             return;

-        updateInputState(cl, ii, context);

+        updateInputState(cl, ii, context, setValue);

     }

     

     public void postUpdateModel(UIComponent comp, InputInfo ii, FacesContext fc)

@@ -222,7 +232,7 @@
         // Clear submitted value

         clearSubmittedValue(input);

     }

-

+    

     public Object getInputValue(UIComponent comp, InputInfo ii, boolean submitted)

     {

         UIInput input = getInputComponent(comp);

@@ -293,6 +303,24 @@
         return submittedValue;

     }

     

+    protected void addAttachedObjects(UIComponent parent, FacesContext context, InputInfo ii, UIComponentBase inputComponent)

+    {

+        InputAttachedObjectsHandler aoh = InputControlManager.getAttachedObjectsHandler();

+        if (aoh!=null)

+            aoh.addAttachedObjects(parent, context, ii.getColumn(), inputComponent);

+    }

+    

+    protected UIInput getFirstInput(List<UIComponent> compList)

+    {

+        for (int i=0; i<compList.size(); i++)

+        {

+            UIComponent child = compList.get(i);

+            if (child instanceof UIInput)

+                return ((UIInput)child);

+        }

+        throw new ItemNotFoundException("UIInput");

+    }

+    

     protected void setInputValue(UIInput input, InputInfo ii)

     {

         // Restore submitted value

@@ -403,7 +431,7 @@
     /* Input helpers */

     protected abstract void createInputComponents(UIComponent parent, InputInfo ii, FacesContext context, List<UIComponent> compList);

 

-    protected abstract void updateInputState(List<UIComponent> compList, InputInfo ii, FacesContext context);

+    protected abstract void updateInputState(List<UIComponent> compList, InputInfo ii, FacesContext context, boolean setValue);

     

     protected UIInput getInputComponent(UIComponent parent)

     {

diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControlManager.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControlManager.java
index 9b309fa..2fc5554 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControlManager.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControlManager.java
@@ -94,6 +94,18 @@
         return controlMap.get(name);

     }

 

+    static InputAttachedObjectsHandler attachedObjectsHandler = new InputAttachedObjectsHandler();

+    

+    public static InputAttachedObjectsHandler getAttachedObjectsHandler()

+    {

+        return attachedObjectsHandler;

+    }

+

+    public static void setAttachedObjectsHandler(InputAttachedObjectsHandler attachedObjectsHandler)

+    {

+        InputControlManager.attachedObjectsHandler = attachedObjectsHandler;

+    }

+

     private static Map<Class<? extends UIComponent>, String> componentTypeMap = new HashMap<Class<? extends UIComponent>, String>();

 

     @SuppressWarnings("unchecked")

diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/RadioInputControl.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/RadioInputControl.java
index 7991309..0f2b0a4 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/RadioInputControl.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/RadioInputControl.java
@@ -36,6 +36,7 @@
 import org.apache.empire.commons.Options;

 import org.apache.empire.data.Column;

 import org.apache.empire.exceptions.InternalException;

+import org.apache.empire.exceptions.InvalidArgumentException;

 import org.apache.empire.exceptions.ItemNotFoundException;

 import org.apache.empire.exceptions.UnexpectedReturnValueException;

 import org.apache.empire.jsf2.app.TextResolver;

@@ -102,56 +103,6 @@
         writer.endElement(HTML_TAG_TABLE);

         writer.endElement(HTML_TAG_DIV);

     }

-

-    @Override

-    protected void createInputComponents(UIComponent parent, InputInfo ii, FacesContext context, List<UIComponent> compList)

-    {

-        HtmlSelectOneRadio input;

-        if (compList.size() == 0)

-        {   // create component

-            input = InputControlManager.createComponent(context, this.inputComponentClass);

-            // setValueExpressionFlag

-            Object value = ii.getValue(false);

-            input.getAttributes().put(RadioInputControl.VALUE_EXPRESSION_FLAG, (value instanceof ValueExpression));

-            // copy Attributes

-            copyAttributes(parent, ii, input);

-            // disabled

-            boolean disabled = ii.isDisabled();

-            input.setDisabled(disabled);

-            // Options

-            Options options = ii.getOptions();

-            boolean addEmpty = getEmptyEntryRequired(ii, disabled) && !options.contains("");

-            String nullText = (addEmpty) ? getNullText(ii) : "";

-            initOptions(input, ii.getTextResolver(), options, addEmpty, nullText);

-            // add

-            compList.add(input);

-        }

-        else

-        { // check type

-            UIComponent comp = compList.get(0);

-            if (!(comp instanceof HtmlSelectOneRadio))

-            {

-                throw new UnexpectedReturnValueException(comp.getClass().getName(), "compList.get");

-            }

-            // cast

-            input = (HtmlSelectOneRadio) comp;

-            // disabled

-            boolean disabled = ii.isDisabled();

-            input.setDisabled(disabled);

-            // Options (sync)

-            Options options = ii.getOptions();

-            boolean addEmpty = getEmptyEntryRequired(ii, disabled) && !options.contains("");

-            String nullText = (addEmpty) ? getNullText(ii) : "";

-            syncOptions(input, ii.getTextResolver(), options, addEmpty, nullText);

-        }

-

-        // style

-        addRemoveDisabledStyle(input, input.isDisabled());

-        addRemoveInvalidStyle(input, ii.hasError());

-

-        // Set Value

-        setInputValue(input, ii);

-    }

     

     @Override

     protected void copyAttributes(UIComponent parent, InputInfo ii, UIInput input, String additonalStyle)

@@ -163,9 +114,38 @@
         // copy

         super.copyAttributes(parent, ii, input, additonalStyle);

     }

+

+    @Override

+    protected void createInputComponents(UIComponent parent, InputInfo ii, FacesContext context, List<UIComponent> compList)

+    {

+        if (!compList.isEmpty())

+            throw new InvalidArgumentException("compList", compList);

+        // create

+        HtmlSelectOneRadio input = InputControlManager.createComponent(context, this.inputComponentClass);

+        // setValueExpressionFlag

+        Object value = ii.getValue(false);

+        input.getAttributes().put(RadioInputControl.VALUE_EXPRESSION_FLAG, (value instanceof ValueExpression));

+        // copy Attributes

+        copyAttributes(parent, ii, input);

+        // disabled

+        boolean disabled = ii.isDisabled();

+        input.setDisabled(disabled);

+        // Options

+        Options options = ii.getOptions();

+        boolean addEmpty = getEmptyEntryRequired(ii, disabled) && !options.contains("");

+        String nullText = (addEmpty) ? getNullText(ii) : "";

+        initOptions(input, ii.getTextResolver(), options, addEmpty, nullText);

+        // add

+        compList.add(input);

+        // style

+        addRemoveDisabledStyle(input, input.isDisabled());

+        addRemoveInvalidStyle(input, ii.hasError());

+        // Set Value

+        setInputValue(input, ii);

+    }

     

     @Override

-    protected void updateInputState(List<UIComponent> compList, InputInfo ii, FacesContext context)

+    protected void updateInputState(List<UIComponent> compList, InputInfo ii, FacesContext context, boolean setValue)

     {

         UIComponent comp = compList.get(0);

         if (!(comp instanceof HtmlSelectOneRadio))

@@ -181,6 +161,14 @@
         boolean addEmpty = getEmptyEntryRequired(ii, disabled) && !options.contains("");

         String nullText = (addEmpty) ? getNullText(ii) : "";

         syncOptions(input, ii.getTextResolver(), options, addEmpty, nullText);

+        // Set Value

+        if (setValue)

+        {   // style

+            addRemoveDisabledStyle(input, input.isDisabled());

+            addRemoveInvalidStyle(input, ii.hasError());

+            // set value

+            setInputValue(input, ii);

+        }

     }

 

     protected boolean getEmptyEntryRequired(InputInfo ii, boolean disabled)

diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/SelectInputControl.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/SelectInputControl.java
index 803751b..425cdc7 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/SelectInputControl.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/SelectInputControl.java
@@ -33,6 +33,7 @@
 import org.apache.empire.commons.Options;

 import org.apache.empire.data.Column;

 import org.apache.empire.exceptions.InternalException;

+import org.apache.empire.exceptions.InvalidArgumentException;

 import org.apache.empire.exceptions.ItemNotFoundException;

 import org.apache.empire.exceptions.UnexpectedReturnValueException;

 import org.apache.empire.jsf2.app.TextResolver;

@@ -71,53 +72,35 @@
     @Override

     protected void createInputComponents(UIComponent parent, InputInfo ii, FacesContext context, List<UIComponent> compList)

     {

-        HtmlSelectOneMenu input;

-        if (compList.size() == 0)

-        {   // create component

-            input = InputControlManager.createComponent(context, this.inputComponentClass);

-            // setValueExpressionFlag

-            Object value = ii.getValue(false);

-            input.getAttributes().put(SelectInputControl.VALUE_EXPRESSION_FLAG, (value instanceof ValueExpression));

-            // copy Attributes

-            copyAttributes(parent, ii, input);

-            // disabled

-            boolean disabled = ii.isDisabled();

-            input.setDisabled(disabled);

-            // Options

-            Options options = getOptions(ii);

-            boolean addEmpty = getEmptyEntryRequired(ii, disabled) && !options.contains("");

-            String nullText = (addEmpty) ? getNullText(ii) : "";

-            initOptions(input, ii.getTextResolver(), options, addEmpty, nullText);

-            // add

-            compList.add(input);

-        }

-        else

-        { // check type

-            UIComponent comp = compList.get(0);

-            if (!(comp instanceof HtmlSelectOneMenu))

-                throw new UnexpectedReturnValueException(comp.getClass().getName(), "compList.get");

-            // cast

-            input = (HtmlSelectOneMenu) comp;

-            // disabled

-            boolean disabled = ii.isDisabled();

-            input.setDisabled(disabled);

-            // Options (sync)

-            Options options = getOptions(ii);

-            boolean addEmpty = getEmptyEntryRequired(ii, disabled) && !options.contains("");

-            String nullText = (addEmpty) ? getNullText(ii) : "";

-            syncOptions(input, ii.getTextResolver(), options, addEmpty, nullText, ii.isInsideUIData());

-        }

-

+        // check params

+        if (!compList.isEmpty())

+            throw new InvalidArgumentException("compList", compList);

+        // create

+        HtmlSelectOneMenu input = InputControlManager.createComponent(context, this.inputComponentClass);

+        // setValueExpressionFlag

+        Object value = ii.getValue(false);

+        input.getAttributes().put(SelectInputControl.VALUE_EXPRESSION_FLAG, (value instanceof ValueExpression));

+        // copy Attributes

+        copyAttributes(parent, ii, input);

+        // disabled

+        boolean disabled = ii.isDisabled();

+        input.setDisabled(disabled);

+        // Options

+        Options options = getOptions(ii);

+        boolean addEmpty = getEmptyEntryRequired(ii, disabled) && !options.contains("");

+        String nullText = (addEmpty) ? getNullText(ii) : "";

+        initOptions(input, ii.getTextResolver(), options, addEmpty, nullText);

+        // add

+        compList.add(input);

         // style

         addRemoveDisabledStyle(input, input.isDisabled());

         addRemoveInvalidStyle(input, ii.hasError());

-

         // Set Value

         setInputValue(input, ii);

     }

     

     @Override

-    protected void updateInputState(List<UIComponent> compList, InputInfo ii, FacesContext context)

+    protected void updateInputState(List<UIComponent> compList, InputInfo ii, FacesContext context, boolean setValue)

     {

         UIComponent comp = compList.get(0);

         if (!(comp instanceof HtmlSelectOneMenu))

@@ -133,6 +116,14 @@
         boolean addEmpty = getEmptyEntryRequired(ii, disabled) && !options.contains("");

         String nullText = (addEmpty) ? getNullText(ii) : "";

         syncOptions(input, ii.getTextResolver(), options, addEmpty, nullText, ii.isInsideUIData());

+        // set value

+        if (setValue)

+        {   // style

+            addRemoveDisabledStyle(input, input.isDisabled());

+            addRemoveInvalidStyle(input, ii.hasError());

+            // set value

+            setInputValue(input, ii);

+        }

     }

 

     protected boolean getEmptyEntryRequired(InputInfo ii, boolean disabled)

diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/TextAreaInputControl.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/TextAreaInputControl.java
index c5dd985..d313ea5 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/TextAreaInputControl.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/TextAreaInputControl.java
@@ -26,6 +26,7 @@
 

 import org.apache.empire.commons.ObjectUtils;

 import org.apache.empire.commons.StringUtils;

+import org.apache.empire.exceptions.InvalidArgumentException;

 import org.apache.empire.exceptions.UnexpectedReturnValueException;

 

 public class TextAreaInputControl extends InputControl

@@ -56,50 +57,29 @@
     @Override

     protected void createInputComponents(UIComponent parent, InputInfo ii, FacesContext context, List<UIComponent> compList)

     {

-        HtmlInputTextarea input;

-        if (compList.size()==0)

-        {   // create component

-            input = InputControlManager.createComponent(context, this.inputComponentClass);

-            // once

-            copyAttributes(parent, ii, input);

-            // cols

-            int cols = getFormatInteger(ii, FORMAT_COLS, FORMAT_COLS_ATTRIBUTE);

-            if (cols>0)

-                input.setCols(cols);

-            // rows

-            int rows = getFormatInteger(ii, FORMAT_ROWS, FORMAT_ROWS_ATTRIBUTE);

-            if (rows>0)

-                input.setRows(rows);

-            // add

-            compList.add(input);

-        }

-        else

-        {   // check type

-            UIComponent comp = compList.get(0);

-            if (!(comp instanceof HtmlInputTextarea))

-                throw new UnexpectedReturnValueException(comp.getClass().getName(), "compList.get");

-            // cast

-            input = (HtmlInputTextarea)comp;

-        }

-

-        // disabled

-        Object dis = ii.getAttributeEx("disabled");

-        if (dis!=null)

-            input.setDisabled(ObjectUtils.getBoolean(dis));

-        // field-readOnly

-        if (ObjectUtils.getBoolean(dis)==false)

-            input.setReadonly(ii.isFieldReadOnly());

-        // style

-        addRemoveDisabledStyle(input, (input.isDisabled() || input.isReadonly()));

-        addRemoveInvalidStyle(input, ii.hasError());

-        

-        // Set Value

-        setInputValue(input, ii);

-        

+        // check params

+        if (!compList.isEmpty())

+            throw new InvalidArgumentException("compList", compList);

+        // create

+        HtmlInputTextarea input = InputControlManager.createComponent(context, this.inputComponentClass);

+        // once

+        copyAttributes(parent, ii, input);

+        // cols

+        int cols = getFormatInteger(ii, FORMAT_COLS, FORMAT_COLS_ATTRIBUTE);

+        if (cols>0)

+            input.setCols(cols);

+        // rows

+        int rows = getFormatInteger(ii, FORMAT_ROWS, FORMAT_ROWS_ATTRIBUTE);

+        if (rows>0)

+            input.setRows(rows);

+        // add

+        compList.add(input);

+        // update

+        updateInputState(compList, ii, context, true);

     }

     

     @Override

-    protected void updateInputState(List<UIComponent> compList, InputInfo ii, FacesContext context)

+    protected void updateInputState(List<UIComponent> compList, InputInfo ii, FacesContext context, boolean setValue)

     {

         UIComponent comp = compList.get(0);

         if (!(comp instanceof HtmlInputTextarea))

@@ -114,6 +94,14 @@
         // field-readOnly

         if (ObjectUtils.getBoolean(dis)==false)

             input.setReadonly(ii.isFieldReadOnly());

+        // Set Value

+        if (setValue)

+        {   // style

+            addRemoveDisabledStyle(input, (input.isDisabled() || input.isReadonly()));

+            addRemoveInvalidStyle(input, ii.hasError());

+            // set value

+            setInputValue(input, ii);

+        }    

     }

 

     @Override

diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/TextInputControl.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/TextInputControl.java
index 6e723c5..bbb5c4a 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/TextInputControl.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/TextInputControl.java
@@ -40,6 +40,7 @@
 import org.apache.empire.commons.StringUtils;

 import org.apache.empire.data.Column;

 import org.apache.empire.data.DataType;

+import org.apache.empire.exceptions.InvalidArgumentException;

 import org.apache.empire.exceptions.UnexpectedReturnValueException;

 import org.apache.empire.jsf2.utils.TagEncodingHelper;

 import org.slf4j.Logger;

@@ -78,68 +79,41 @@
     @Override

     protected void createInputComponents(UIComponent parent, InputInfo ii, FacesContext context, List<UIComponent> compList)

     {

-        HtmlInputText input;

-        if (compList.size() == 0)

-        { // create component

-            input = InputControlManager.createComponent(context, this.inputComponentClass);

-            // once

-            copyAttributes(parent, ii, input);

-            // language

-            input.setLang(ii.getLocale().getLanguage());

-            // maxlength

-            int maxLength = getMaxInputLength(ii);

-            if (maxLength > 0)

-            {

-                input.setMaxlength(maxLength);

-            }

-            // add

-            compList.add(input);

-

-            // add unit

-            String unit = getUnitString(ii);

-            if (StringUtils.isNotEmpty(unit))

-            {   // add the unit

-                compList.add(createUnitLabel("eUnit", ii, unit));

-            }

-            // add hint

-            String hint = StringUtils.toString(ii.getAttribute("hint"));

-            if (StringUtils.isNotEmpty(hint) && !ii.isDisabled())

-            {   // add the hint (if not an empty string!)

-                compList.add(createUnitLabel("eInputHint", ii, hint));

-            }

-        }

-        else

-        { // check type

-            UIComponent comp = compList.get(0);

-            if (!(comp instanceof HtmlInputText))

-            {

-                throw new UnexpectedReturnValueException(comp.getClass().getName(), "compList.get");

-            }

-            // cast

-            input = (HtmlInputText) comp;

-        }

-

-        // disabled

-        Object dis = ii.getAttributeEx("disabled");

-        if (dis != null)

+        // check params

+        if (!compList.isEmpty())

+            throw new InvalidArgumentException("compList", compList);

+        // create

+        HtmlInputText input = InputControlManager.createComponent(context, this.inputComponentClass);

+        // once

+        copyAttributes(parent, ii, input);

+        // language

+        input.setLang(ii.getLocale().getLanguage());

+        // maxlength

+        int maxLength = getMaxInputLength(ii);

+        if (maxLength > 0)

         {

-            input.setDisabled(ObjectUtils.getBoolean(dis));

+            input.setMaxlength(maxLength);

         }

-        // field-readOnly

-        if (ObjectUtils.getBoolean(dis) == false)

-        {

-            input.setReadonly(ii.isFieldReadOnly());

+        // add

+        compList.add(input);

+        // add unit

+        String unit = getUnitString(ii);

+        if (StringUtils.isNotEmpty(unit))

+        {   // add the unit

+            compList.add(createUnitLabel("eUnit", ii, unit));

         }

-        // style

-        addRemoveDisabledStyle(input, (input.isDisabled() || input.isReadonly()));

-        addRemoveInvalidStyle(input, ii.hasError());

-

-        // set value

-        setInputValue(input, ii);

+        // add hint

+        String hint = StringUtils.toString(ii.getAttribute("hint"));

+        if (StringUtils.isNotEmpty(hint) && !ii.isDisabled())

+        {   // add the hint (if not an empty string!)

+            compList.add(createUnitLabel("eInputHint", ii, hint));

+        }

+        // update

+        updateInputState(compList, ii, context, true);

     }

 

     @Override

-    protected void updateInputState(List<UIComponent> compList, InputInfo ii, FacesContext context)

+    protected void updateInputState(List<UIComponent> compList, InputInfo ii, FacesContext context, boolean setValue)

     {

         UIComponent comp = compList.get(0);

         if (!(comp instanceof HtmlInputText))

@@ -158,6 +132,14 @@
         {

             input.setReadonly(ii.isFieldReadOnly());

         }

+        // set value

+        if (setValue)

+        {   // style

+            addRemoveDisabledStyle(input, (input.isDisabled() || input.isReadonly()));

+            addRemoveInvalidStyle(input, ii.hasError());

+            // set value

+            setInputValue(input, ii);

+        }

     }

 

     protected UIComponent createUnitLabel(String tagStyle, InputInfo ii, String value)