10 Replies Latest reply on Jul 26, 2006 7:39 AM by bfo81

    Stale Session Objects ? DataModelSelection Problems

    kryptontri

      JBoss 4.0.4.GA
      JBoss Seam 1.0.1 GA

      Hi

      I am having issues dealing with 1 to many relationships and DataModelSelection, in that
      session data i think, doesn't seem to be cleared, this issue happens sporadically, i am looking for a pattern to see when it fails.

      Basically, I have a set of rate objects that i can add for a contractor's page

      This is the vew


      <div class="section">
      <fieldset>
      <div class="entry_small">
      <c:choose>
      <c:when test='${ratesPageManager.rates == null or ratesPageManager.rowCount == 0}'>
      Empty Rates
      </c:when>
      <c:otherwise>
      <h:dataTable value="#{ratesPageManager.rates}" var="item" rendered="#{ratesPageManager.rowCount>0}" rowClasses="rvgRowOne,rvgRowTwo">
      <h:column>
      <f:facet name="header"><h:outputText value="Duration"/></f:facet>
      <h:outputText value="#{item.duration}"/>
      </h:column>
      <h:column>
      <f:facet name="header"><h:outputText value="Unit"/></f:facet>
      <h:outputText value="#{item.unit}"/>
      </h:column>
      <h:column>
      <f:facet name="header"><h:outputText value="Currency"/></f:facet>
      <h:outputText value="#{item.currency}"/>
      </h:column>
      <h:column>
      <f:facet name="header"><h:outputText value="Cost"/></f:facet>
      <h:outputText value="#{item.cost}"/>
      </h:column>
      <h:column>
      <f:facet name="header">Action</f:facet>
      <h:commandLink action="#{ratesPageManager.deleteRate}">Delete</h:commandLink>
      </h:column>

      </h:dataTable>
      </c:otherwise>
      </c:choose>

      </div>
      </fieldset>

      <br/>
      <fieldset>
      <div class="entry_small">
      <h:form>
      <table>
      <tr>
      <td><div class="label"><h:outputLabel for="duration">Duration:</h:outputLabel></div></td>
      <td><div class="select"><h:selectOneMenu id="duration" value="#{rate.duration}"><f:selectItems value="#{ratesManager.durations}"/></h:selectOneMenu></div></td>
      <td><div class="label"><h:outputLabel for="unit">Unit:</h:outputLabel></div></td>
      <td><div class="select"><h:selectOneMenu id="unit" value="#{rate.unit}"><f:selectItems value="#{ratesManager.units}"/></h:selectOneMenu></div></td>
      <td><div class="label"><h:outputLabel for="currency">Currency:</h:outputLabel></div></td>
      <td><div class="select"><h:selectOneMenu id="currency" value="#{rate.currency}"><f:selectItems value="#{ratesManager.currencys}"/></h:selectOneMenu></div></td>
      <td><div class="label"><h:outputLabel for="cost">Cost:</h:outputLabel></div></td>
      <td><div class="select"><h:selectOneMenu id="cost" value="#{rate.cost}"><f:selectItems value="#{ratesManager.costs}"/></h:selectOneMenu></div></td>
      </tr>
      <tr>
      <td colspan="8">
      <h:commandButton value="Add Rate" action="#{ratesPageManager.addRate}" class="button"/>
      </td>
      </tr>
      </table>
      </h:form>
      </div>
      </fieldset>
      </div>


      For the Session bean behind this


      @Stateful
      @Scope(ScopeType.SESSION)
      @Name("ratesPageManager")
      @Interceptors(SeamInterceptor.class)
      @LoggedIn
      public class RatesPageManagerBean implements RatesPageManager {

      private static final Log log = LogFactory.getLog(RatesPageManagerBean.class.getName());

      @In
      @Out
      @Valid
      private User user;

      @In
      @Out
      @Valid
      private Profile profile;

      @In(required = false)
      @Out
      @Valid
      private RatesPage ratesPage;

      @PersistenceContext
      private EntityManager em;

      @In
      private transient FacesContext facesContext;

      @DataModel
      private List<Rate> rates = new ArrayList();

      @Out(required=false)
      @DataModelSelection
      private Rate selectedRate;

      @In(required = false, create = true)
      @Out(required=false)
      private Rate rate;

      public Rate getRate() {
      return rate;
      }

      public void setRate(Rate rate) {
      this.rate = rate;
      }

      @IfInvalid(outcome = REDISPLAY)
      public String create() {
      if (profile.getRatesPage() == null) {
      em.persist(ratesPage);
      profile.setRatesPage(ratesPage);
      profile = em.merge(profile);
      return "viewRatesPage";
      } else {
      facesContext.addMessage(null, new FacesMessage("RatesPage already exists"));
      return "viewProfile";
      }
      }

      public String select() {
      profile = user.getProfile();
      ratesPage = profile.getRatesPage();
      rates.clear();
      rates.addAll(ratesPage.getRates());
      clearRatesOnDisplay();
      return "viewRatesPage";
      }


      private boolean isUnSet(Rate rateToCheck) {

      boolean isOk = (
      (rateToCheck.getCost() == 0) || (rateToCheck.getCurrency().equals("-")) ||
      (rateToCheck.getDuration() == 0) || (rateToCheck.getUnit().equals("-"))
      );
      log.info("Rate check:: cost=" + rateToCheck.getCost() + " currency=" +rateToCheck.getCurrency()
      + " duration=" + rateToCheck.getDuration() + " unit=" + rateToCheck.getUnit());
      return isOk;
      }


      public String addRate() {
      log.info("addRate() called");

      if(isUnSet(rate)) {
      log.warn("Failed rates check");
      rate = null;
      facesContext.addMessage(null, new FacesMessage("Please enter rates"));
      return "viewRatesPage";
      }
      log.info("trying to add rate ..");
      rate.setRatesPage(ratesPage);
      em.persist(rate);
      ratesPage.addRate(rate);
      ratesPage = em.merge(ratesPage);
      profile = em.merge(profile);
      log.info("Persisted! and trying to remove");
      clearRatesOnDisplay();
      return select();
      }

      public String deleteRate() {
      log.info("deleteRate() called, removing " + selectedRate);
      rates.remove(selectedRate);
      ratesPage.removeRate(selectedRate);
      em.remove(selectedRate);
      clearRatesOnDisplay();
      return "viewRatesPage";
      }

      public List getRates() {
      log.info("getRates() called size = " + this.rates.size());
      return this.rates;
      }
      public void setRates(List in) {
      this.rates = in;
      }
      public int getRowCount() {
      return this.rates.size();
      }



      public String delete() {
      profile.setGalleryPage(null);
      em.remove(ratesPage);
      profile = em.merge(profile);
      return "viewProfile";
      }

      @IfInvalid(outcome = REDISPLAY)
      public String edit() {
      ratesPage = em.merge(ratesPage);
      return "viewRatesPage";
      }

      @Destroy
      @Remove
      public void destroy() {
      }

      private void clearRatesOnDisplay() {
      Contexts.getPageContext().remove("rate");
      rate = null;
      selectedRate = null;
      }


      The rate object which forms the many side of the relationship

      @Entity
      @Name("rate")
      @Scope(SESSION)
      public class Rate implements Serializable {

      protected int Id = 0;

      protected int duration = 0;
      protected String unit = null;
      protected String currency = null;
      protected int cost = 0;
      protected RatesPage ratesPage = null;

      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      public int getId() {
      return Id;
      }

      public void setId(int id) {
      Id = id;
      }

      @NotNull
      public int getDuration() {
      return duration;
      }

      public void setDuration(int duration) {
      this.duration = duration;
      }

      @NotNull
      public String getUnit() {
      return unit;
      }

      public void setUnit(String unit) {
      this.unit = unit;
      }

      @NotNull
      public String getCurrency() {
      return currency;
      }

      public void setCurrency(String currency) {
      this.currency = currency;
      }

      @NotNull
      public int getCost() {
      return cost;
      }

      public void setCost(int cost) {
      this.cost = cost;
      }

      @ManyToOne
      @JoinColumn(name = "RATES_PAGE_ID")
      public RatesPage getRatesPage() {
      return ratesPage;
      }

      public void setRatesPage(RatesPage ratesPage) {
      this.ratesPage = ratesPage;
      }

      public boolean equals(Object o) {
      if (this == o) return true;
      if (o == null || getClass() != o.getClass()) return false;

      final Rate rate = (Rate) o;

      if (Id != rate.Id) return false;
      if (cost != rate.cost) return false;
      if (duration != rate.duration) return false;
      if (currency != null ? !currency.equals(rate.currency) : rate.currency != null) return false;
      if (ratesPage != null ? !ratesPage.equals(rate.ratesPage) : rate.ratesPage != null) return false;
      if (unit != null ? !unit.equals(rate.unit) : rate.unit != null) return false;

      return true;
      }

      public int hashCode() {
      int result;
      result = Id;
      result = 29 * result + duration;
      result = 29 * result + (unit != null ? unit.hashCode() : 0);
      result = 29 * result + (currency != null ? currency.hashCode() : 0);
      result = 29 * result + cost;
      result = 29 * result + (ratesPage != null ? ratesPage.hashCode() : 0);
      return result;
      }

      public String toString() {
      StringBuffer buffer = new StringBuffer();
      buffer.append("Id=").append(Id);
      buffer.append(" Duration=").append(duration);
      buffer.append(" Unit=").append(unit);
      buffer.append(" Currency=").append(currency);
      buffer.append(" Cost=").append(cost);
      // buffer.append(" RatesPageId=").append(ratesPage.getId());
      return buffer.toString();
      }

      }



      What happens is that the debug server log will show an old rate, perhaps the
      previous one add or that exists in the session and displays


      2006-07-24 18:07:50,055 DEBUG [org.jboss.seam.Component] selected row: Id=39 Duration=1 Unit=Week Currency=$ Cost=150


      I added the clearRatesOnDisplay method to nullify any existence of state, in
      an attempt to ensure that the select menus in the view are cleaned.

      Any ideas people?

      TIA Krypt


        • 1. Re: Stale Session Objects ? DataModelSelection Problems
          pmuir

          It would be easier to help if you posted a simplified example (lose the irrelvant fields) with some better formatting (some indentation would ease reading). The second part of your view isn't valid XML. Try the code format in the forum as well :) Sorry, I tried to understand what you were doing but it was just too much to plough through!

          • 2. Re: Stale Session Objects ? DataModelSelection Problems
            kryptontri

            Sorry about the bad formatting and being lazy. I am tying to provide
            add/remove functionality through a page, where by there is a 1 to
            many relationship.

            If I now take the messages example and modify it
            to add messages (remove already exists) I cannot get this to work
            properly, can anyone point me in the right direction or to an example
            that does this ie managed relationships for objects?

            In the view - messages.jsp I added (I tried make it format nice, but for some mysterious
            reason it does not want to, i have previoued this severla times :-( )


            <!-- Added New Messages -->
            <h:form>
            <table>
            <tr>
            <td>
            <h:outputLabel for="title">Title:</h:outputLabel>
            </td>
            <td>
            <h:inputText id="title" value="#{message.title}"/>
            </td>
            <td>
            <h:outputLabel for="text">Text:</h:outputLabel>
            </td>
            <td>
            <h:inputText id="text" value="#{message.text}"/>
            </td>
            </tr>
            <tr>
            <td colspan="8">
            <h:commandButton value="Add Message" action="#{messageManager.addMessage}"/>
            </td>
            </tr>
            </table>
            </h:form>
            <!-- End Add New Messages -->


            For the MessageManager

            @Local
            public interface MessageManager
            {
            public void findMessages();
            public void select();
            public void delete();
            public void destroy();
            public void addMessage();
            }


            For the MessageManagerBean

            public class MessageManagerBean implements Serializable, MessageManager
            {

            @DataModel
            private List<Message> messageList;

            @DataModelSelection
            @Out(required=false)
            private Message selectedMessage;

            // --- Added ----- //
            @In(required = false, create = true)
            @Out(required=false)
            private Message message;

            @PersistenceContext(type=EXTENDED)
            private EntityManager em;

            @Factory("messageList")
            public void findMessages()
            {
            messageList = em.createQuery("from Message msg order by msg.datetime desc").getResultList();
            }

            public void select()
            {
            selectedMessage.setRead(true);
            }

            public void delete()
            {
            messageList.remove(selectedMessage);
            em.remove(selectedMessage);
            message=null;
            }

            @Remove @Destroy
            public void destroy() {}

            // --- Added ----- //
            public void addMessage() {
            message.setRead(false);
            message.setDatetime(new Date());
            em.persist(message);
            messageList.add(message);
            //messageList = em.merge(messageList);
            message = null;
            }

            }


            Do you see where I am going wrong ? As it stands I can add 1 message, but then
            I cannot add a second and the input box never gets cleared.

            I am after a clean example that adds/removes etc ? Any ideas ? TIA

            • 3. Re: Stale Session Objects ? DataModelSelection Problems
              kryptontri

              I think I need to look at the issues example, which has something in there

              • 4. Re: Stale Session Objects ? DataModelSelection Problems
                kryptontri

                I looked at the issue example, its a bit more complex and i can't find the simple example i am looking for. Can anyone post any example code if they have done something simple like this pls ?

                • 5. Re: Stale Session Objects ? DataModelSelection Problems
                  kryptontri

                  Can anyone help me morph the messages example to add messages ? I tried, but what i have done as posted above seems to fail ? Any ideas pls?

                  • 6. Re: Stale Session Objects ? DataModelSelection Problems
                    bfo81

                    Sounds like there could be a JSF error. Add <h:messages /> to find out ;).

                    Plus: The <h:form> Tag should come right after the <f:view>. Don't ask me why it's been left out in this example, and it surprises me that the original example works without form tags...

                    • 7. Re: Stale Session Objects ? DataModelSelection Problems
                      kryptontri

                      thanks bfo81, I'll try that in next couple of hours and see if that does the trick.

                      • 8. Re: Stale Session Objects ? DataModelSelection Problems
                        kryptontri

                        I tried move the tags as you suggested, but now the submit does not push the data the backend., I think the form tags must be inside the view tag.

                        • 9. Re: Stale Session Objects ? DataModelSelection Problems
                          bfo81

                          Well, I only meant that the STARTING form-tag should be moved up, so that it's behind the view tag. Maybe I expressed myself minsunderstandingly ;)

                          Here's what I mean:

                          ...
                          <f:view>
                           <h:form>
                           ... all the rest ...
                           </h:form>
                          </f:view>
                          ...


                          • 10. Re: Stale Session Objects ? DataModelSelection Problems
                            bfo81

                            And please don't forget to put a <h:messages /> somewhere between ;).