6 Replies Latest reply on May 24, 2008 12:32 AM by Dan Allen

    Design question: should JSF components be accessed in session EJBs?

    Ben Moore Newbie

      None of the Seam examples use binding="" attributes on Faceletes pages. None of the Seam examples reference any UIComponent from Seam components (whether they be EJBs or POJOs).


      So the answer to my question would appear to be no, but I cannot figure out the following:


      I have an html table which displays the name/value pairs in a Map. Values can be edited by the user. Without writing code to walk to HTML table row-by-row (see below), how can I update the Map on user submit? The code I'm trying to avoid in my EJB...



         // Walk the HtmlDataTable to get updated name/value pairs 
          for ( int i = 0; i < dataTable.getRowCount(); i++ ) {
            dataTable.setRowIndex(i);
            Iterator iter = dataTable.getChildren().iterator();
            while ( iter.hasNext() ) {
              UIComponent column = (UIComponent) iter.next();
              Iterator columnChildren = column.getChildren().iterator();
              String name = null, value = null;
              while ( columnChildren.hasNext() ) {
                UIComponent child = (UIComponent) columnChildren.next();
                String temp = (String) ((HtmlOutputText) child).getValue();
                if ( child instanceof HtmlOutputText )
                  name = temp;
                else if ( child instanceof HtmlInputText )
                  value = temp;
              }
              if ( name != null && value != null )
                properties.put(name, value);

        • 1. Re: Design question: should JSF components be accessed in session EJBs?
          Mark Michalek Newbie

          What is the value of your HtmlInputText bound to?  Can you pull the updated value from that object?

          • 2. Re: Design question: should JSF components be accessed in session EJBs?
            Ben Moore Newbie

            The HtmlInputText isn't bound to anything right now:



            <rich:dataTable value="#{properties}" var="mapEntry">     
              <rich:column>
              <f:facet name="header">Name</f:facet>
                <h:outputLabel for="value" value="#{mapEntry.key}"/>
              </rich:column>
              <rich:column>
              <f:facet name="header">Value</f:facet>
                <h:inputText id="value" value="#{mapEntry.value}"/>
              </rich:column>
            </rich:dataTable> 



            properties is a Map<String, String>

            • 3. Re: Design question: should JSF components be accessed in session EJBs?
              Ben Moore Newbie

              Ben Moore wrote on Apr 02, 2008 08:59 PM:


              The HtmlInputText isn't bound to anything right now:


              <rich:dataTable value="#{properties}" var="mapEntry">     
                <rich:column>
                <f:facet name="header">Name</f:facet>
                  <h:outputLabel for="value" value="#{mapEntry.key}"/>
                </rich:column>
                <rich:column>
                <f:facet name="header">Value</f:facet>
                  <h:inputText id="value" value="#{mapEntry.value}"/>
                </rich:column>
              </rich:dataTable> 



              properties is a Map<String, String>


              Mistake, of course. The input boxes are bound to the Map, but changing them doesn't change the Map.


              How else can this be done without using JSF in the session EJB?

              • 4. Re: Design question: should JSF components be accessed in session EJBs?
                Pete Muir Master

                Ben Moore wrote on Apr 02, 2008 07:52 PM:


                None of the Seam examples use binding="" attributes on Faceletes pages. None of the Seam examples reference any UIComponent from Seam components (whether they be EJBs or POJOs).

                So the answer to my question would appear to be no, but I cannot figure out the following:



                Almost certainly not a good idea - you are tying the view too closely to the business layer.


                Assuming you use a <c:forEach /> this should work.

                • 5. Re: Design question: should JSF components be accessed in session EJBs?
                  Ben Moore Newbie

                  Pete Muir wrote on Apr 05, 2008 20:29:


                  Assuming you use a <c:forEach /> this should work.


                  Sorry to dig up this old thread, but I'm back to this same problem again. The map isn't getting updated when the user makes changes. Pete, where exactly should I be using <c:forEach/> ? Are you saying I should use that instead of <rich:dataTable/> to render the labels and input boxes?


                  Thanks,
                  Ben

                  • 6. Re: Design question: should JSF components be accessed in session EJBs?
                    Dan Allen Master
                    I'll agree that this isn't the most shining part of JSF, but there is a way to accomplish this thanks to Seam.

                    First, your problem is that Map.Entry is not writable, so you cannot bind directly to the value property. What you need is two context variables, one native map, one Seam's DataModel wrapper. Here is the action bean:


                    `@Name("propertyEditor")
                    @Scope(ScopeType.CONVERSATION)
                    public class PropertyEditorAction implements Serializable {
                         @DataModel
                         private Map<String, String> propertiesModel;
                         
                         @Out
                         private Map<String, String> properties;
                         
                         @Begin(join = true) @Factory("propertiesModel")
                         public void retrieveProperties() {
                              this.propertiesModel = this.properties;
                         }
                         
                         public void save() {
                         }
                         
                         public void setProperties(Map<String, String> properties) {
                              this.properties = properties;
                         }
                    }`

                    Then in the UI:

                    `<rich:dataTable value="#{propertiesModel}" var="mapEntry">
                      <rich:column>
                      <f:facet name="header">Name</f:facet>
                        <h:outputLabel for="value" value="#{mapEntry.key}"/>
                      </rich:column>
                      <rich:column>
                      <f:facet name="header">Value</f:facet>
                        <h:inputText id="value" value="#{properties[mapEntry.key]}"/>
                      </rich:column>
                    </rich:dataTable>`

                    Notice how I have the native map and the data model work together to negotiate the update.

                    <span style="font-size:x-small;">As a side note, I first tried |#{propertiesModel.wrappedData[mapEntry.key]}|, but it didn't work because Seam's map data model returns a transient map that disappears, not the native one.</span>