package com.ChasySoft.client.dataSources; import com.google.gwt.core.client.JavaScriptObject; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import com.google.gwt.user.client.rpc.AsyncCallback; import com.smartgwt.client.core.DataClass; import com.smartgwt.client.data.DSRequest; import com.smartgwt.client.data.DSResponse; import com.smartgwt.client.data.DataSource; import com.smartgwt.client.data.Record; import com.smartgwt.client.util.BooleanCallback; import com.smartgwt.client.util.SC; import com.smartgwt.client.widgets.grid.ListGridRecord; public abstract class GwtRpcDataSource extends DataSource { static final String DO_NOT_HANDLE = "doNotHandle"; private static final String DO_NOT_PROPAGATE = "doNotPropagate"; private GwtRpcDataSourceEndpoint fetchEndpoint; private GwtRpcDataSourceEndpoint updateEndpoint; private GwtRpcDataSourceEndpoint addEndpoint; private GwtRpcDataSourceEndpoint removeEndpoint; private boolean batchMode = false; private Object[] parameters = new Object[0]; public GwtRpcDataSource() { setClientOnly(true); } public void setFetchEndpoint(GwtRpcDataSourceEndpoint fetchEndpoint) { this.fetchEndpoint = fetchEndpoint; } /* * Note if the GWT-RPC call fails the internal datasource data will be out of * sync with dependent widgets. This will become obvious the next time a * widget syncs to the datasource without triggering a fetch. One workaround * is to call fetchData again in postFailure, but since that kicks off an * extra server request that is not the default behavior. */ public void setUpdateEndpoint(GwtRpcDataSourceEndpoint updateEndpoint) { this.updateEndpoint = updateEndpoint; } public void setAddEndpoint(GwtRpcDataSourceEndpoint addEndpoint) { this.addEndpoint = addEndpoint; } public void setRemoveEndpoint(GwtRpcDataSourceEndpoint removeEndpoint) { this.removeEndpoint = removeEndpoint; } /* * If bulkMode is true the first parameter in the variable arguments for * update/add/remove will be a ListGridRecord[] instead of a ListGridRecord. * This means the endpoint will only be called once instead of n times where * n is the length of the ListGridRecord array. */ public void setBatchMode(boolean batchMode) { this.batchMode = batchMode; } public void setParameters(Object... parameters) { this.parameters = parameters; } protected void transformResponse(DSResponse response, DSRequest request, Object data) { if (request.getOperationType() != null) { Record[] records = response.getData(); switch (request.getOperationType()) { case ADD: if (request.getAttributeAsBoolean(DO_NOT_PROPAGATE) != null && request.getAttributeAsBoolean(DO_NOT_PROPAGATE).equals(Boolean.TRUE)) { response.setStatus(-1); } else if (request.getAttributeAsBoolean(DO_NOT_HANDLE) == null || request.getAttributeAsBoolean(DO_NOT_HANDLE).equals(Boolean.FALSE)) { response.setStatus(-1); executeAdd(records, request); } break; case FETCH: executeFetch(request); break; case REMOVE: if (request.getAttributeAsBoolean(DO_NOT_HANDLE) == null || request.getAttributeAsBoolean(DO_NOT_HANDLE).equals(Boolean.FALSE)) { executeRemove(records, request); response.setStatus(-1); } break; case UPDATE: if (request.getAttributeAsBoolean(DO_NOT_HANDLE) == null || request.getAttributeAsBoolean(DO_NOT_HANDLE).equals(Boolean.FALSE)) { response.setStatus(-1); executeUpdate(records, request); } break; default: break; } } super.transformResponse(response, request, data); } protected abstract Record populateRecord(Record record, T object); private void executeUpdate(final Record[] records, DSRequest request) { if (batchMode) { updateEndpoint.callEndpoint(new AsyncCallback() { public void onFailure(Throwable caught) { updateEndpoint.postFailure(caught); } public void onSuccess(Object result) { for (int i = 0; i < records.length; i++) { Record Record = records[i]; DSRequest req = new DSRequest(); req.setAttribute(DO_NOT_HANDLE, true); updateData(Record, null, req); updateEndpoint.postSuccess(result); } updateEndpoint.postSuccess(result); } }, request, (Object) records, parameters); } else { for (int i = 0; i < records.length; i++) { final Record Record = records[i]; updateEndpoint.callEndpoint(new AsyncCallback() { public void onFailure(Throwable caught) { updateEndpoint.postFailure(caught); } public void onSuccess(Object result) { DSRequest req = new DSRequest(); req.setAttribute(DO_NOT_HANDLE, true); updateData(Record, null, req); updateEndpoint.postSuccess(result); } }, request, Record, parameters); } } } private void executeRemove(final Record[] records, DSRequest request) { if (batchMode) { removeEndpoint.callEndpoint(new AsyncCallback() { public void onFailure(Throwable caught) { for (int i = 0; i < records.length; i++) { Record Record = records[i]; DSRequest req = new DSRequest(); req.setAttribute(DO_NOT_HANDLE, true); addData(Record, null, req); } removeEndpoint.postFailure(caught); } public void onSuccess(Object result) { for (int i = 0; i < records.length; i++) { Record Record = records[i]; DSRequest req = new DSRequest(); req.setAttribute(DO_NOT_PROPAGATE, true); addData(Record, null, req); DSRequest req2 = new DSRequest(); req2.setAttribute(DO_NOT_HANDLE, true); removeData(Record, null, req2); } removeEndpoint.postSuccess(result); } }, request, (Object) records, parameters); } else { for (int i = 0; i < records.length; i++) { final Record Record = records[i]; removeEndpoint.callEndpoint(new AsyncCallback() { public void onFailure(Throwable caught) { DSRequest req = new DSRequest(); req.setAttribute(DO_NOT_HANDLE, true); addData(Record, null, req); removeEndpoint.postFailure(caught); } public void onSuccess(Object result) { DSRequest req = new DSRequest(); req.setAttribute(DO_NOT_PROPAGATE, true); addData(Record, null, req); DSRequest req2 = new DSRequest(); req2.setAttribute(DO_NOT_HANDLE, true); removeData(Record, null, req2); removeEndpoint.postSuccess(result); } }, request, Record, parameters); } } } private void executeFetch(DSRequest request) { fetchEndpoint.callEndpoint(new AsyncCallback() { public void onFailure(Throwable caught) { fetchEndpoint.postFailure(caught); } public void onSuccess(Object object) { Collection resultSet = fetchEndpoint.transformResult(object); DataClass[] testData = getTestData(); Map recordSet = new HashMap(); for (int i = 0; i < testData.length; i++) { recordSet.put(testData[i].getAttribute(getPrimaryKeyFieldName()), testData[i]); } for (Entry recordEntry : recordSet.entrySet()) { DSRequest req = new DSRequest(); req.setAttribute(DO_NOT_HANDLE, true); removeData(recordEntry.getValue(), null, req); } recordSet.clear(); for (final T result : resultSet) { DSRequest req = new DSRequest(); req.setAttribute(DO_NOT_HANDLE, true); Record record = populateRecord(new Record() { public JavaScriptObject getJsObj() { return JavaScriptObject.createObject(); } }, result); addData(record, null, req); } fetchEndpoint.postSuccess(object); } }, request, parameters); } private void executeAdd(final Record[] records, DSRequest request) { if (batchMode) { addEndpoint.callEndpoint(new AsyncCallback() { public void onFailure(Throwable caught) { for (int i = 0; i < records.length; i++) { Record Record = records[i]; DSRequest req = new DSRequest(); req.setAttribute(DO_NOT_HANDLE, true); removeData(Record, null, req); } addEndpoint.postFailure(caught); } public void onSuccess(Object result) { for (int i = 0; i < records.length; i++) { Record Record = records[i]; DSRequest req = new DSRequest(); req.setAttribute(DO_NOT_HANDLE, true); addData(Record, null, req); } addEndpoint.postSuccess(result); } }, request, records, parameters); } else { for (int i = 0; i < records.length; i++) { final Record Record = records[i]; addEndpoint.callEndpoint(new AsyncCallback() { public void onFailure(Throwable caught) { DSRequest req = new DSRequest(); req.setAttribute(DO_NOT_HANDLE, true); removeData(Record, null, req); addEndpoint.postFailure(caught); } public void onSuccess(Object result) { DSRequest req = new DSRequest(); req.setAttribute(DO_NOT_HANDLE, true); addData(Record, null, req); addEndpoint.postSuccess(result); } }, request, Record, parameters); } } } }