Announcement

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

    GWT-RPC, ListGrids and transformResponse

    I would like to wire a listgrid to a datasource that uses gwt-rpc as it's transport. I would like the grid to populate with data when the page loads. I would like the grid to periodically fetch new data from the server and update existing records. I would like to connect a form to the datasource for creating new records. I would only like the new records to appear in the listgrid if my gwt-rpc call to the server is successful.

    I have been using the techniques described in these two threads:

    http://forums.smartclient.com/showthread.php?t=4183
    http://forums.smartclient.com/showthread.php?t=3538

    and have encountered a couple of problems I have been unable to work around.

    The first problem is around the adding new data. I've overridden transformResponse and have a block for add requests. The problem is that I'm calling the addData method from the block for fetch requests and that method seems to asynchronously call addData. The result is there is no way for me to determine if transformResponse is being called for an addData initiated by the form submission or from fetch being called on the DataSource. This creates two problems: a) I always end up calling my gwt-rpc request to add once for each row that gets returned by a fetch and b) when the form is initiating the add I can't change the status to fail to prevent the data from going in the grid, this means even if the gwt-rpc call fails the data is already added in the grid.

    The second problem is with updating data. When a fetch is called there is no way for me to determine if a record is already in the datasource. This means there is no way to know if I should call addData or updateData for reach record. Ideally there would be some way on the datasource to lookup a record by it's primary key.

    I will attach the code in a followup post.

    Thanks,
    Benjamin
    Last edited by benjaminberry; 5 Mar 2009, 08:17. Reason: Make links live

    #2
    This is the DataSource code I have been using.

    Code:
    package com.mycompany.client;
    
    import java.util.List;
    
    import com.google.gwt.core.client.GWT;
    import com.google.gwt.user.client.rpc.AsyncCallback;
    import com.mycompany.services.StockService;
    import com.mycompany.services.StockServiceAsync;
    import com.smartgwt.client.data.DSRequest;
    import com.smartgwt.client.data.DSResponse;
    import com.smartgwt.client.data.DataSource;
    import com.smartgwt.client.data.fields.DataSourceFloatField;
    import com.smartgwt.client.data.fields.DataSourceTextField;
    import com.smartgwt.client.widgets.grid.ListGridRecord;
    
    public class StockGWTRPCDataSource extends DataSource {
       private boolean initialized = false;
    
       public StockGWTRPCDataSource() {
          setClientOnly(true);
          DataSourceTextField symbolDataField = new DataSourceTextField("symbol", "Symbol");
          symbolDataField.setPrimaryKey(true);
          DataSourceFloatField priceDataField = new DataSourceFloatField("price", "Price");
          priceDataField.setCanEdit(false);
          DataSourceFloatField changeDataField = new DataSourceFloatField("change", "Change");
          changeDataField.setCanEdit(false);
    
          setFields(symbolDataField, priceDataField, changeDataField);
       }
    
       @Override
       protected Object transformRequest(DSRequest request) {
          if (request.getOperationType() != null) {
             switch (request.getOperationType()) {
                 case ADD:
                     //executeAdd(lstRec, true);
                     break;
                 case FETCH:
                     //executeFetch();
                     break;
                 case REMOVE:
                     //executeRemove(lstRec);
                     break;
                 case UPDATE:
                     //executeAdd(lstRec, false);
                     break;
    
                 default:
                     break;
             }
         }
         return super.transformRequest(request);
       }
    
       @Override
       protected void transformResponse(DSResponse response, DSRequest request, Object data) {
          if (request.getOperationType() != null) {
             ListGridRecord[] lstRec = response.getData();
             switch (request.getOperationType()) {
                 case ADD:
                     if(initialized) {
                        response.setStatus(-1);
                        executeAdd(lstRec);
                     }
                     break;
                 case FETCH:
                     executeFetch();
                     break;
                 case REMOVE:
                     //executeRemove(lstRec);
                     break;
                 case UPDATE:
                     //executeAdd(lstRec, false);
                     break;
    
                 default:
                     break;
             }
         }
         super.transformResponse(response, request, data);
       }
    
       private void executeAdd(ListGridRecord[] records) {
             StockServiceAsync stockService = GWT.create(StockService.class);
             
             stockService.addStock(records[0].getAttribute("symbol"), new AsyncCallback<String>() {
    
             public void onFailure(Throwable caught) {
                // TODO Auto-generated method stub
                
             }
    
             public void onSuccess(String result) {
                // TODO Auto-generated method stub
                
             }});      
       }
    
       private void executeFetch() {
          StockServiceAsync stockService = GWT.create(StockService.class);
          
          stockService.listStocks(new AsyncCallback<List<StockPrice>>() {
    
             public void onFailure(Throwable caught) {
                // TODO Auto-generated method stub
                
             }
    
             public void onSuccess(List<StockPrice> result) {
                for (StockPrice stockPrice : result) {
                   if(initialized) {
                      updateData(new StockListGridRow(stockPrice.getSymbol(), stockPrice.getPrice(), stockPrice.getChange()));
                   } else {
                      addData(new StockListGridRow(stockPrice.getSymbol(), stockPrice.getPrice(), stockPrice.getChange()));
                   }
                }
                if(!initialized) {
                   initialized = true;
                }
             }});
       }
       
       
    }
    The stuff about the initialized boolean was my clumsy attempt to solve these problems.

    Benjamin

    Comment


      #3
      DSResponse

      Hi Ben,

      I can just support your question since I face the same problem here.

      transfromResponse is a good place to trigger the RPC call, however as the RPC call is asynchronous we do not have access to the DSResponse in the callback object anymore and therefore we cannot provide the original calling object (grid, form, ...) with the call result.

      Any help would really be appreciated.

      Thanks.

      E

      Comment


        #4
        I managed to find a solution to both my problems.

        I solved the first issue by adding an attribute to my addData and updateData requests when they are initiated by the fetch operation. That way I know not to handle the subsequent calls in my transformResponse code.

        I solved the second issue by first issuing an updateData with a handler. The handler simply checks if the data payload is null, if it was, I assume no update took place because there was no corresponding record so I immediately issue an addData request.

        This is actually still not sufficient because it will not remove items that are already in the recordset but were not returned by the fetch. I think ultimately I will have call getTestData, compare the two datasets, remove the entries not in the new dataset, add the entries not in the old dataset, and update the others.

        Here is my updated DataSource for anyone who is curious:

        Code:
        package com.mycompany.client;
        
        import java.util.List;
        
        import com.google.gwt.core.client.GWT;
        import com.google.gwt.user.client.rpc.AsyncCallback;
        import com.mycompany.services.StockService;
        import com.mycompany.services.StockServiceAsync;
        import com.smartgwt.client.data.DSCallback;
        import com.smartgwt.client.data.DSRequest;
        import com.smartgwt.client.data.DSResponse;
        import com.smartgwt.client.data.DataSource;
        import com.smartgwt.client.data.fields.DataSourceFloatField;
        import com.smartgwt.client.data.fields.DataSourceIntegerField;
        import com.smartgwt.client.data.fields.DataSourceTextField;
        import com.smartgwt.client.widgets.grid.ListGridRecord;
        
        public class StockGWTRPCDataSource extends DataSource {
        
           public StockGWTRPCDataSource() {
              setClientOnly(true);
              DataSourceIntegerField idDataField = new DataSourceIntegerField("id");
              idDataField.setPrimaryKey(true);
              DataSourceTextField symbolDataField = new DataSourceTextField("symbol", "Symbol");
              DataSourceFloatField priceDataField = new DataSourceFloatField("price", "Price");
              priceDataField.setCanEdit(false);
              DataSourceFloatField changeDataField = new DataSourceFloatField("change", "Change");
              changeDataField.setCanEdit(false);
        
              setFields(idDataField, symbolDataField, priceDataField, changeDataField);
           }
        
           @Override
           protected void transformResponse(DSResponse response, DSRequest request, Object data) {
              if (request.getOperationType() != null) {
                 ListGridRecord[] lstRec = response.getData();
                 switch (request.getOperationType()) {
                     case ADD:
                         if(Boolean.FALSE.equals(request.getAttributeAsBoolean("fetching"))) {
                            response.setStatus(-1);
                            executeAdd(lstRec);
                         }
                         break;
                     case FETCH:
                         executeFetch();
                         break;
                     case REMOVE:
                         executeRemove(lstRec);
                         break;
                     case UPDATE:
                        if(Boolean.FALSE.equals(request.getAttributeAsBoolean("fetching"))) {
                           executeEdit(lstRec);
                        }
                        break;
        
                     default:
                         break;
                 }
             }
             super.transformResponse(response, request, data);
           }
        
           private void executeEdit(ListGridRecord[] lstRec) {
              if(lstRec.length != 1) {
                 return;
              }
              StockServiceAsync stockService = GWT.create(StockService.class);
              stockService.editStock(lstRec[0].getAttributeAsInt("id"), lstRec[0].getAttribute("symbol"), new AsyncCallback<String>() {
        
                 public void onFailure(Throwable caught) {
                    
                 }
        
                 public void onSuccess(String result) {
        
                 }});   
           }
        
           private void executeRemove(ListGridRecord[] lstRec) {
              StockServiceAsync stockService = GWT.create(StockService.class);
        
              for (int i = 0; i < lstRec.length; i++) {
                 ListGridRecord listGridRecord = lstRec[i];
                 stockService.removeStock(listGridRecord.getAttributeAsInt("id"), new AsyncCallback<String>() {
        
                    public void onFailure(Throwable caught) {
                       
                    }
        
                    public void onSuccess(String result) {
        
                    }});   
              }
                    
           }
        
           private void executeAdd(final ListGridRecord[] records) {
                 StockServiceAsync stockService = GWT.create(StockService.class);
                 
                 stockService.addStock(records[0].getAttribute("symbol"), new AsyncCallback<String>() {
        
                 public void onFailure(Throwable caught) {
                    // TODO Auto-generated method stub
                    
                 }
        
                 public void onSuccess(String result) {
                    DSRequest req = new DSRequest();
                    req.setAttribute("fetching", true);
                    addData(new StockListGridRow(records[0].getAttributeAsInt("id"), records[0].getAttribute("symbol"), 0, 0), null, req);            
                 }});      
           }
        
           private void executeFetch() {
              StockServiceAsync stockService = GWT.create(StockService.class);
              
              stockService.listStocks(new AsyncCallback<List<StockPrice>>() {
        
                 public void onFailure(Throwable caught) {
                    // TODO Auto-generated method stub
                    
                 }
        
                 public void onSuccess(List<StockPrice> result) {
                    for (final StockPrice stockPrice : result) {
                       DSRequest r = new DSRequest();
                       r.setAttribute("fetching", true);
                       updateData(new StockListGridRow(stockPrice.getId(), stockPrice.getSymbol(), stockPrice.getPrice(), stockPrice.getChange()), new DSCallback() {
        
                          public void execute(DSResponse response, Object rawData, DSRequest request) {
                             if(rawData == null) {
                                DSRequest req = new DSRequest();
                                req.setAttribute("fetching", true);
                                addData(new StockListGridRow(stockPrice.getId(), stockPrice.getSymbol(), stockPrice.getPrice(), stockPrice.getChange()), null, req);
                             }
                             
                          }}, r);
                    }
                 }});
           }
           
           
        }

        Comment


          #5
          Thanks, i was stuck on the exact same problem.

          Comment


            #6
            I would really appreciate it if someone working on the project would reply to this thread. My concern is this: what are the plans concerning a gwt-rpc datasource.

            You have mentioned on other threads examples were coming soon. You mentioned in the 1.0b2 release notes that enhancements were made for handling gwt-rpc datasources. I have yet to see either.

            What I and others have done seem to be hacks. I need to be able to justify the technology internally and to do that I will need some mechanism for using gwt-rpc with datasources. Should I be writing my own based on the work here? Is one forthcoming from Sanjiv? What is the timeline if that is the case? Will it be in the LGPL edition or will we need to purchase a license to use it? These all seem like questions the community deserves an answer to.

            Benjamin

            Comment


              #7
              I've overridden transformResponse and have a block for add requests. The problem is that I'm calling the addData method from the block for fetch requests and that method seems to asynchronously call addData.
              Hi Benjamin,
              I understand the issue you're running into and although do-able, it's not super convenient integrating gwt-rpc due to the points you raise. A couple of key API's have been incorporated into SmartClient to support getting gwt-rpc integration to be smoother. I will have to validate and then incorporate them.

              You could proceed the path you're taking and update the code when the feature is incorporated. This is a priority along with other features like i18n and exposing the ResultSet API. So "star" the issue in tracker if it is important to you.

              Sanjiv

              Comment

              Working...
              X