0 Replies Latest reply on Jul 8, 2008 10:54 AM by gonzalad

    Issue : ManagedEntityIdentityInterceptor and nested conversation

    gonzalad Apprentice

      Hello,



      Issue :




      This issue happens when you :



      1. use a non jpa component (let's call it incrementer) in a root conversation,

      2. navigate to a page executed in a nested conversation displaying the same non jpa component and a jpa component.

      3. when you come back to the first page, List fields of the non jpa component have been nullified (by ManagedEntityIdentityInterceptor in step 2).



      Since the first page doesn't use any entityManager (this is important), ManagedEntityIdentityInterceptor isn't completely executed (touchedContextsExist() returns false).


      In the second page, ManagedEntityIdentityInterceptor  is executed on both components since touchedContextsExist() now returns true. So, incrementer.values field is nullified.


      When I go back to the first page and click on refresh : since nested conversation has ended, touchedContextsExist() returns false and ManagedEntityIdentityInterceptor isn't anymore applied to my incrementer component. And incrementer.values is null.


      This issue is related to http://jira.jboss.com/jira/browse/JBSEAM-1814, and can be resolved with the same solution : just be a more restrictive on ManagedEntityIdentityInterceptor.isRef() method (if it's a collection, test if the first non nul element in the collection is a jpa entity) :


      Should I open a JIRA issue ?


      Thanks



      Sample solution (ManagedEntityIdentityInterceptor.isRef())




      @SuppressWarnings("unchecked")
      private boolean isRef(Object value) {
          //TODO: could do better by checking if the
          //      collection really contains an entity
          if (value==null) {
              return false;
          }
          Object lObject = null;
          if (value instanceof Collection) {
              lObject = getFirstNonNullObject ((Collection)value); 
          } else if(value instanceof Map) {
              lObject = getFirstNonNullObject (((Map)value).values()); 
          } else {
              lObject = value;
          }
          return lObject == null ? false : Seam.getEntityClass(lObject.getClass()) != null;
      }





      Seam version used : 2.0.2.SP1



      Test case :


      To reproduce the issue :




      1. just click on 'Go to incrementer page link'.

      2. click a few times on 'Increment' link.

      3. click on Go back (you should see the previous incremented value - everything ok).

      4. click on 'Refresh' : incrementer has no value now !.





      [1] incrementer component (non jpa)


      @Name("incrementer")
      @Scope(ScopeType.CONVERSATION)
      public class Incrementer {
          private List<Integer> values;
          
          public Incrementer() {
              values = new ArrayList<Integer>();
              values.add(0);
          }
          public List<Integer> getValues() {
              return values;
          }
      
          public void setValues(List<Integer> aValues) {
              values = aValues;
          }
          
          public void increment() {
              if (values == null) {
                  values = new ArrayList<Integer>();
                  values.add(0);
              }
              values.set (0, values.get(0)+1);
          }
      }
      



      [2] index.xhtml starts a long running conversation :



      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <html xmlns="http://www.w3.org/1999/xhtml"
                         xmlns:ui="http://java.sun.com/jsf/facelets"
                            xmlns:h="http://java.sun.com/jsf/html"
                            xmlns:f="http://java.sun.com/jsf/core"
                          xmlns:a4j="http://richfaces.org/a4j"
                            xmlns:s="http://jboss.com/products/seam/taglib">
        <head>
           <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
           <link href="screen.css" rel="stylesheet" type="text/css" />
        </head>
        <body>
          <div class="body">
              <div class="actionButtons">
                <s:link view="/main.xhtml" value="Begin Long Running" action="#{conversation.begin}" propagation="none"/>
              </div>
           </div>
        </body>
      </html>
      



      [3] main.xhtml shows the incrementer component values :


      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <html xmlns="http://www.w3.org/1999/xhtml"
                         xmlns:ui="http://java.sun.com/jsf/facelets"
                            xmlns:h="http://java.sun.com/jsf/html"
                            xmlns:f="http://java.sun.com/jsf/core"
                          xmlns:a4j="http://richfaces.org/a4j"
                            xmlns:s="http://jboss.com/products/seam/taglib">
        <head>
           <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
        </head>
        <body>
        
          <div class="body">
            <h1>Incrementer values : </h1>
                <s:fragment rendered="#{not empty incrementer.values}">
                     <ul>
                          <ui:repeat value="#{incrementer.values}" var="sample">
                               <li>#{sample}</li>
                          </ui:repeat>
                     </ul>
                </s:fragment>
                <s:fragment rendered="#{empty incrementer.values}">
                     No Value !!!
                </s:fragment>
                      
                 <h:messages styleClass="message"/>
              <div class="actionButtons">
                <s:link view="/main.xhtml" value="Refresh"/>
                <s:link view="/nest.xhtml" value="Go To incrementer page" propagation="nest"/>
              </div>
            </div>
        </body>
      </html>
      




      [4] nest.xhtml :


      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <html xmlns="http://www.w3.org/1999/xhtml"
                         xmlns:ui="http://java.sun.com/jsf/facelets"
                            xmlns:h="http://java.sun.com/jsf/html"
                            xmlns:f="http://java.sun.com/jsf/core"
                          xmlns:a4j="http://richfaces.org/a4j"
                            xmlns:s="http://jboss.com/products/seam/taglib">
        <head>
                <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
        </head>
        <body>
          <div class="body">
            <h1>Incrementer values : </h1>
                     <s:fragment rendered="#{not empty incrementer.values}">
                          <ul>
                               <ui:repeat value="#{incrementer.values}" var="sample">
                                    <li>#{sample}</li>
                               </ui:repeat>
                          </ul>
                     </s:fragment>
                     <s:fragment rendered="#{empty incrementer.values}">
                          No Value !!!
                     </s:fragment>
            <div class="dialog">
                          <i>sample jpa block, please ignore</i>
              <table>
                <tr class="prop">
                  <td class="name">First Name:</td>
                  <td class="value">#{contact.firstName}</td>
                </tr>
                          </table>
             </div>
              <div class="actionButtons">
                <s:link view="/nest.xhtml" value="Increment" action="#{incrementer.increment}"/>
                <s:link view="/main.xhtml" value="Go back" propagation="end"/>
              </div>
            </div>
        </body>
      </html>
      




      [5] Contact.java (just use Contact entity bundled in Seam contact samples)


      [6] components.xml :



      <?xml version="1.0" encoding="UTF-8"?>
      <components xmlns="http://jboss.com/products/seam/components"
                  xmlns:core="http://jboss.com/products/seam/core"
                  xmlns:fwk="http://jboss.com/products/seam/framework"
                        xmlns:transaction="http://jboss.com/products/seam/transaction"
                  xmlns:persistence="http://jboss.com/products/seam/persistence"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation=
                      "http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.0.xsd 
                       http://jboss.com/products/seam/framework http://jboss.com/products/seam/framework-2.0.xsd
                       http://jboss.com/products/seam/persistence http://jboss.com/products/seam/persistence-2.0.xsd 
                       http://jboss.com/products/seam/transaction http://jboss.com/products/seam/transaction-2.0.xsd
                       http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.0.xsd">
      
          <persistence:entity-manager-factory
                  name="contactlistEntityManagerFactory" auto-create="true"/>
         
         <persistence:managed-persistence-context name="entityManager" auto-create="true"
                                 entity-manager-factory="#{contactlistEntityManagerFactory}"/>
      
          <factory name="contact" value="#{contactHome.instance}"/>
          
          <fwk:entity-home name="contactHome" 
                   entity-class="org.jboss.seam.example.contactlist.Contact" />
      
          <fwk:entity-query name="contacts" scope="conversation"
                     max-results="5">
              <fwk:ejbql>from Contact</fwk:ejbql>
              <fwk:order>lastName</fwk:order>
              <fwk:restrictions>
                  <value>lower(firstName) like lower( concat( #{exampleContact.firstName}, '%' ) )</value>
                  <value>lower(lastName) like lower( concat( #{exampleContact.lastName}, '%' ) )</value>
              </fwk:restrictions>
          </fwk:entity-query>
          
          <component name="exampleContact"
                    class="org.jboss.seam.example.contactlist.Contact" scope="conversation"/>
      
      </components>
      



      [7] pages.xml :


      <?xml version="1.0" encoding="UTF-8"?>
      <pages xmlns="http://jboss.com/products/seam/pages"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.0.xsd" no-conversation-view-id="/main.xhtml">
         
         <page view-id="/nest.xhtml">
                <action execute="#{contactHome.setId(1001)}"/>
         </page>
         
         <exception>
            <end-conversation/>
            <redirect view-id="/search.xhtml">
                <message>Unexpected failure</message>
            </redirect>
         </exception>
         
      </pages>