Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    DataSource Cache Update Clears Sort and fires FieldStateChangedEvent

    Hi Isomorphic,

    We have a case, where updating the DataSource cache would appear to be reverting our list grid sort, and causing a field state change event, and we are looking for some guidance on why this might be happening. I have captured the stack trace below. The documentation for the field state change handler claims, "Notification method executed when columns are resized or reordered, or fields are shown or hidden. Has no default implementation.", which is makes it unclear how such an event would be fired for a DataSource cache update.

    Thanks

    SmartClient Version: v10.1p_2016-04-08/Pro Deployment (built 2016-04-08)

    Code:
    (Suspended (breakpoint at line 468 in XXXXXListGrid$8))
        XXXXXListGrid$8.onFieldStateChanged(FieldStateChangedEvent) line: 468
        FieldStateChangedEvent.dispatch(FieldStateChangedHandler) line: 111    
        FieldStateChangedEvent.dispatch(EventHandler) line: 1    
        FieldStateChangedEvent(GwtEvent<H>).dispatch(Object) line: 1    
        EventBus.dispatchEvent(Event<H>, H) line: 40    
        HandlerManager$Bus(SimpleEventBus).doFire(Event<H>, Object) line: 193    
        HandlerManager$Bus(SimpleEventBus).fireEvent(Event<?>) line: 88    
        HandlerManager.fireEvent(GwtEvent<?>) line: 127    
        TaskList(Widget).fireEvent(GwtEvent<?>) line: 129    
        GeneratedMethodAccessor83.invoke(Object, Object[]) line: not available    
        DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43    
        Method.invoke(Object, Object...) line: 497    
        MethodAdaptor.invoke(Object, Object...) line: 103    
        MethodDispatch.invoke(JsValue, JsValue[], JsValue) line: 71    
        OophmSessionHandler.invoke(BrowserChannelServer, BrowserChannel$Value, int, BrowserChannel$Value[]) line: 172    
        BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer$SessionHandlerServer) line: 338    
        BrowserChannelServer.invokeJavascript(CompilingClassLoader, JsValueOOPHM, String, JsValueOOPHM[], JsValueOOPHM) line: 219    
        ModuleSpaceOOPHM.doInvoke(String, Object, Class<?>[], Object[]) line: 136    
        ModuleSpaceOOPHM(ModuleSpace).invokeNative(String, Object, Class<?>[], Object[]) line: 576    
        ModuleSpaceOOPHM(ModuleSpace).invokeNativeObject(String, Object, Class<?>[], Object[]) line: 284    
        JavaScriptHost.invokeNativeObject(String, Object, Class<?>[], Object[]) line: 91    
        Impl.apply(Object, Object, Object) line: not available    
        Impl.entry0(Object, Object, Object) line: 356    
        GeneratedMethodAccessor43.invoke(Object, Object[]) line: not available    
        DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43    
        Method.invoke(Object, Object...) line: 497    
        MethodAdaptor.invoke(Object, Object...) line: 103    
        MethodDispatch.invoke(JsValue, JsValue[], JsValue) line: 71    
        OophmSessionHandler.invoke(BrowserChannelServer, BrowserChannel$Value, int, BrowserChannel$Value[]) line: 172    
        BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer$SessionHandlerServer) line: 338    
        BrowserChannelServer.invokeJavascript(CompilingClassLoader, JsValueOOPHM, String, JsValueOOPHM[], JsValueOOPHM) line: 219    
        ModuleSpaceOOPHM.doInvoke(String, Object, Class<?>[], Object[]) line: 136    
        ModuleSpaceOOPHM(ModuleSpace).invokeNative(String, Object, Class<?>[], Object[]) line: 576    
        ModuleSpaceOOPHM(ModuleSpace).invokeNativeVoid(String, Object, Class<?>[], Object[]) line: 304    
        JavaScriptHost.invokeNativeVoid(String, Object, Class<?>[], Object[]) line: 107    
        DataSource.updateCaches(DSResponse) line: not available    
        ClientUtils.updateDsCache(DataSource, DSOperationType, Record, XXXXXListGrid) line: 1795    
        ClientUtils.updateDsCache(XXXXXFormGenerator, DSOperationType, Record) line: 1765    
        ClientUtils$37.execute(DSResponse, Object, DSRequest) line: 1686    
        ClientUtils$3.execute(DSResponse, Object, DSRequest) line: 402    
        NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]    
        NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62    
        DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43    
        Method.invoke(Object, Object...) line: 497    
        MethodAdaptor.invoke(Object, Object...) line: 103    
        MethodDispatch.invoke(JsValue, JsValue[], JsValue) line: 71    
        OophmSessionHandler.invoke(BrowserChannelServer, BrowserChannel$Value, int, BrowserChannel$Value[]) line: 172    
        BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer$SessionHandlerServer) line: 338    
        BrowserChannelServer.invokeJavascript(CompilingClassLoader, JsValueOOPHM, String, JsValueOOPHM[], JsValueOOPHM) line: 219    
        ModuleSpaceOOPHM.doInvoke(String, Object, Class<?>[], Object[]) line: 136    
        ModuleSpaceOOPHM(ModuleSpace).invokeNative(String, Object, Class<?>[], Object[]) line: 576    
        ModuleSpaceOOPHM(ModuleSpace).invokeNativeObject(String, Object, Class<?>[], Object[]) line: 284    
        JavaScriptHost.invokeNativeObject(String, Object, Class<?>[], Object[]) line: 91    
        Impl.apply(Object, Object, Object) line: not available    
        Impl.entry0(Object, Object, Object) line: 356    
        GeneratedMethodAccessor43.invoke(Object, Object[]) line: not available    
        DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43    
        Method.invoke(Object, Object...) line: 497    
        MethodAdaptor.invoke(Object, Object...) line: 103    
        MethodDispatch.invoke(JsValue, JsValue[], JsValue) line: 71    
        OophmSessionHandler.invoke(BrowserChannelServer, BrowserChannel$Value, int, BrowserChannel$Value[]) line: 172    
        BrowserChannelServer.reactToMessages(BrowserChannelServer$SessionHandlerServer) line: 293    
        BrowserChannelServer.processConnection() line: 547    
        BrowserChannelServer.run() line: 364    
        Thread.run() line: 745

    #2
    Some additional logging information.

    Code:
    15:20:54.103:XRP9:DEBUG:ResultSet:isc_ResultSet_9 (dataSource: xxxxx, created by: isc_xxxxxList_0):updated cache: 0 row(s) added, 1 row(s) updated, 0 row(s) removed.
    15:20:54.134:XRP9:INFO:aria:ARIA state: selected: true, set on element: [TRElement]{nodeName:TR}
    15:20:54.139:XRP9:INFO:sorting:isc_xxxxxList_0:Entering setSort
    15:20:54.145:XRP9:INFO:sorting:isc_xxxxxList_0:In setSort - marking field groupNames for removal
    15:20:54.149:XRP9:INFO:sorting:isc_xxxxxList_0:null or zero-length sortSpecifiers - unsorting only
    15:20:54.155:XRP9:INFO:sorting:isc_xxxxxList_0:Returning unmodified sort specifiers[
    
    ]

    Comment


      #3
      Hi Isomorphic,

      I have reproduced the issue in a standalone test case. Once loaded, click on any record in the list to perform a cache update; Sort is cleared and FieldStateChange event is fired.

      Thanks

      sandbox7.ds.xml
      Code:
      <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
      <DataSource xmlns:fmt="WEB-INF/" ID="sandbox7" serverType="generic">
          <fields>
              <field name="id" type="text" primaryKey="true" canEdit="false">
                  <title>UUID</title>
              </field>
              <field name="name" type="text" length="255" required="true">
                  <title>Name</title>
              </field>
              <field name="groupNames" type="text" multiple="true" canFilter="false" canEdit="false"> 
                  <title>Group Names</title>
              </field>
          </fields>
          <serverObject lookupStyle="new" className="com.sandbox.server.Sandbox7DS"/>
      </DataSource>
      Sandbox7 EntryPoint
      Code:
      public class Sandbox7 implements EntryPoint {
      
          @Override
          public void onModuleLoad() {
      
              final ListGrid list = new ListGrid();
              list.setWidth100();
              list.setHeight100();
              list.setDataSource(DataSource.get("sandbox7"));
              list.setDataFetchMode(FetchMode.PAGED);
              list.setAutoFitFieldsFillViewport(Boolean.TRUE);
              list.setAutoFitWidthApproach(AutoFitWidthApproach.BOTH);
              list.setAutoFitFieldWidths(Boolean.TRUE);
              list.setCanFreezeFields(Boolean.FALSE);
              list.setCanGroupBy(Boolean.FALSE);
              list.setRecordComponentPoolingMode(RecordComponentPoolingMode.RECYCLE);
              list.setAlternateRecordStyles(Boolean.TRUE);
              list.setAutoFetchData(Boolean.TRUE);
              list.setShowRollOver(Boolean.FALSE);
      
              list.setViewState(
                      "({field:[{name:\"name\"},{name:\"groupNames\"},{name:\"id\",visible:false}],sort:{fieldName:\"groupNames\",sortDir:\"descending\",sortSpecifiers:[{property:\"groupNames\",direction:\"descending\"}]}})");
      
              list.addFieldStateChangedHandler(new FieldStateChangedHandler() {
      
                  @Override
                  public void onFieldStateChanged(FieldStateChangedEvent event) {
                      SC.warn("onFieldStateChanged");
                  }
              });
      
              list.addRecordClickHandler(new RecordClickHandler() {
                  @Override
                  public void onRecordClick(RecordClickEvent event) {
                      ListGridRecord r = new ListGridRecord();
                      r.setAttribute("id", "1");
                      r.setAttribute("name", "Item1");
                      r.setAttribute("groupNames", new String[] { "Group1" });
                      DSResponse cacheResponse = new DSResponse();
                      cacheResponse.setDataSource(list.getDataSource().getID());
                      cacheResponse.setData(r);
                      cacheResponse.setOperationType(DSOperationType.UPDATE);
                      list.getDataSource().updateCaches(cacheResponse);
                  }
              });
      
              list.show();
          }
      }

      Sandbox7DS
      Code:
      public class Sandbox7DS {
      
          public Sandbox7DS() {}
      
          public DSResponse fetch(final DSRequest req) {
              DSResponse resp = new DSResponse();
              resp.setStartRow(req.getStartRow());
              resp.setEndRow(req.getEndRow());
              resp.setTotalRows(1000);
              resp.setData(getTestData(req.getStartRow(), req.getEndRow()));
              return resp;
          }
      
          private List<Map<String, Object>> getTestData(long startRow, long endRow) {
              List<Map<String, Object>> rList = new ArrayList<>();
      
              HashMap<String, Object> r;
              String id;
              String groupName;
              for (long i = startRow; i <= endRow; i++) {
                  r = new HashMap<String, Object>();
                  id = Long.toString(i);
                  r.put("id", id);
                  r.put("name", "Item" + id);
                  groupName = "Group" + id;
                  r.put("groupNames", new String[] { groupName });
                  rList.add(r);
              }
      
              return rList;
          }
      }

      Comment


        #4
        This is by design - see the docs for resultSet.updatePartialCache. There's no reliable way to place an updated record in a partial cache where we are relying on the server for sort direction. So we leave the updated record at its current position and temporarily clear the sort, since the displayed data is necessarily no longer sorted.

        Comment


          #5
          Hi Isomorphic,

          reading this thread I have a general question regarding a non-ordered paging ListGrid.
          Oracle (and I assume other RDBMS as well) does not guarantee any order when SELECTing data without an ORDER BY-clause. As the server sends a new request when the user scrolls on the client, this request could return the data in a different order (especially when partitions/parallel processing are involved).
          Example:
          ListGrid can display 1000 records and gets 75 per fetch.
          On start record 1-75 are loaded from a first SELECT..
          On scroll records 76-150 from a second SELECT-result are loaded. These may or may not be the records 76-150 the first select (that JDBC resultset is not available anymore at that point).

          Can a ListGrid/ResultSet handle this situation? Shouldn't it warn when it has to display unsorted data that requires paging?
          I assume that in real life applications the data should always sorted by some column anyway by default, so that a missing sort is a reason to warn.

          Best regards
          Blama

          Comment


            #6
            Oracle and other DBs document no guaranteed order without a sort, but in reality, will return the same order unless there are modifications, or certain query features are used, and in some other esoteric circumstances.

            If you don't have a solution in place for concurrent modification (detecting changes and setting the invalidateCache flag), then worrying about non-deterministic DB order is a bit silly, as that's a much rarer circumstance.

            Comment


              #7
              Hi Isomorphic,

              I agree. Way more seldom (and most ListGrids will have an order applied anyway).

              I was also thinking about "how does the client get to know about changes in already received data) and how to solve this. Now I know the correct wording (concurrent modification) and how to solve it (DSResponse.setInvalidateCache()). I know that I will need it eventually, so thanks a lot for the pointer.

              Best regards
              Blama

              Comment


                #8
                Hi Isomorphic,

                With respect to "clearing" the Sort, this doesn't seem to be accurate. If we have a Sort on any other field, that isn't multiple="true", the Sort is not cleared under this scenario. You can demonstrate this by simply changing the ViewState in the provided example to Sort on the "name" column instead. The Sort is never cleared under this comparable scenario.

                In our case, when a user clicks on a record, we fetch the latest version of the record for display in a Form, and we want consistency between the record displayed in the List and the Form currently displaying the newly fetched record.

                We have always used this approach, and aside from this particular use case we just discovered, it has been working perfectly fine.

                Are you sure there isn't some special case here? We thought perhaps with the multiple="true", there was some kind of Array value comparison issue.

                Thanks

                Comment


                  #9
                  So the issue here is that you are seeing an unsort when there has not actually been a change to the data? We can check on that.

                  However, it sounds like you are doing this cache update precisely because there *could* have been some changes to the data, and that's expected to cause an unsort (if one of the current sort fields was changed). Is that a problem?

                  Comment


                    #10
                    That's correct, the sort field value did not change yet the sort was cleared.


                    Other fields, that aren't part of the sort specifier, can change without causing the sort to be cleared, correct?


                    Thanks

                    Comment


                      #11
                      Right, we only unsort if a field we are sorting on was changed.

                      Comment


                        #12
                        Hi Isomorphic,

                        I wanted to follow up and confirm that you are still looking at the issue where the sort is being cleared even when the multi-valued field which is being sorted on did not change.

                        Thank you

                        Comment


                          #13
                          Hi Isomorphic,

                          Have you been able to reproduce the issue with the provided sample case? Please let me know if you need anything further from me.

                          Thank you kindly.

                          Comment


                            #14
                            Hi Isomorphic,

                            I acknowledge you are probably busy over there, however, I am going to reach out again for some kind of update on this post.

                            Have you been able to reproduce our issue? Is a change being considered?

                            Thank you

                            Comment


                              #15
                              Hi
                              Sorry for the delay on this. Yes - this is in progress and we'll let you know when we get a resolution in (probably Monday)

                              Regards
                              Isomorphic Software

                              Comment

                              Working...
                              X