Class DSResponse

java.lang.Object
com.isomorphic.base.Base
com.isomorphic.rpc.BaseResponse<DSResponse>
com.isomorphic.datasource.DSResponse
All Implemented Interfaces:
com.isomorphic.base.IAutoConfigurable

public class DSResponse extends BaseResponse<DSResponse>
Response object to be populated by server-side code responding to a DSRequest.
  • Constructor Details

    • DSResponse

      public DSResponse()
      Creates an empty DSResponse. Status code defaults to STATUS_SUCCESS
    • DSResponse

      public DSResponse(int status)
      Creates a DSResponse with the specified status code.
      Parameters:
      status - the status code (one of the static STATUS_* codes on this class)
    • DSResponse

      public DSResponse(Object data)
      Creates a DSResponse with the specified data payload.
      Parameters:
      data - the payload of the response - equivalent to setData()
    • DSResponse

      public DSResponse(Object data, int status)
      Creates a DSResponse with the specified data payload and status code.
      Parameters:
      data - the payload of the response - equivalent to setData()
      status - the status code (one of the static STATUS_* codes on this class)
      See Also:
    • DSResponse

      public DSResponse(DataSource dataSource)
      Creates a DSResponse with the specified dataSource.
      Parameters:
      dataSource - the DataSource associated with this DSResponse
      See Also:
    • DSResponse

      public DSResponse(DataSource dataSource, int status)
      Creates a DSResponse with the specified dataSource and status code.
      Parameters:
      dataSource - the DataSource associated with this DSResponse
      status - the status code (one of the static STATUS_* codes on this class)
      See Also:
    • DSResponse

      public DSResponse(DataSource dataSource, Object data)
      Creates a DSResponse with the specified dataSource and data payload
      Parameters:
      dataSource - the DataSource associated with this DSResponse
      data - the payload of the response - equivalent to setData()
      See Also:
    • DSResponse

      public DSResponse(DataSource dataSource, Object data, int status)
      Creates a DSResponse with the specified dataSource, data payload and status code.
      Parameters:
      dataSource - the DataSource associated with this DSResponse
      data - the payload of the response - equivalent to setData()
      status - the status code (one of the static STATUS_* codes on this class)
      See Also:
  • Method Details

    • getOperationType

      public String getOperationType()
      Returns the operationType associated with this DSResponse.
      Returns:
      the DSResponse's operationType, or null if it is unset
    • setOperationType

      public DSResponse setOperationType(String value)
      Set the operationType associated with this DSResponse.

      Parameters:
      value - the operationType
      Returns:
      the DSResponse
    • setProperty

      public DSResponse setProperty(String key, Object value)
      Set an arbitrary property of the DSResponse, so that the value will be visible to custom JavaScript code on the client-side DSResponse object.

      The value parameter will be translated to JavaScript by the JSTranslater.

      For example, if you were to call:

          dsResponse.setProperty("totalRowsIsApproximate", Boolean.TRUE);
       
      JavaScript code on the client could then access "dsResponse.totalsRowsIsApproximate" from any method that receives the DSResponse, eg, DataSource.transformResponse(). In the case of SmartGWT, you will need to call getAttribute("totalsRowsIsApproximate").

      This API is easily misused. setProperty should only be used to pass metadata about the request, similar to the existing DSResponse properties like startRow/endRow and status. The following are bad patterns:

      • returning extra data. You should instead use queuing (see the JavaScript method RPCManager.startQueue()) to submit multiple independent requests in one HTTP turnaround. By returning extra data as a DSResponse property, you make it impossible to fetch the extra data independently.
      • preserving state during a network turnaround. The client-side DSRequest is generally passed to every client-side method that receives a DSResponse, so you can access properties such as dsRequest.data and dsRequest.oldValues, as well as any custom properties you set on the DSRequest, without having to have the server add those properties to the DSResponse.
      Returns:
      the DSResponse
    • getProperty

      public Object getProperty(String key)
      Returns an arbitrary property of the DSResponse that has previously been set with setProperty(String, Object)
      Parameters:
      key - the key of the property to return
      Returns:
      The value of the requested property, or null if it has never been set
    • getBypassDataFilter

      public Boolean getBypassDataFilter()
      This method returns true if this DSResponse will bypass the normal data filter pipeline (i.e dropExtraFields, valueXPath evaluation, etc) and simply serialize the provided data to the client. This setting also applies to getRecord().
      Returns:
      Boolean.TRUE if this DSResponse will bypass extra fields; otherwise Boolean.FALSE
      See Also:
    • setBypassDataFilter

      public DSResponse setBypassDataFilter(Boolean value)
      This method sets the DSResponse's behavior with regard to the normal data filter pipeline (i.e dropExtraFields, valueXPath evaluation, etc).
      One use case for this flag is to suppress automatic valueXPath derivation on the response in cases where you have postprocessing logic that has already converted the response into client-consumable records.
      Returns:
      the DSResponse
      See Also:
    • getDropExtraFields

      public Boolean getDropExtraFields()
      This method returns true if this DSResponse will automatically trim the fields in its data member to just those fields declared in the DataSource. This is the default for normal, non-custom DataSource operations. This method also applies to getRecord()
      Returns:
      Boolean.TRUE if this DSResponse will drop extra fields; otherwise Boolean.FALSE
      See Also:
    • setDropExtraFields

      public DSResponse setDropExtraFields(Boolean value)
      This method sets the DSResponse's behavior with regard to extra fields in the data it returns. If set to true, only the fields declared in the DataSource will be returned by the DSResponse; all other fields will be automatically trimmed off. If set to false, the DSResponse will return all fields.
      Returns:
      the DSResponse
      See Also:
    • getAffectedRows

      public long getAffectedRows()
      For operations that modify data, this method returns the number of rows affected by the change. This is set by the built-in ISC datasources.
      Returns:
      number of affected rows
    • getInvalidateCache

      public boolean getInvalidateCache()
      Returns the current value of invalidateCache
      Returns:
      current value of invalidateCache
    • setInvalidateCache

      public DSResponse setInvalidateCache(boolean invalidateCache)
      Setting invalidateCache to true triggers the client-side ResultSet to drop its existing cache. If you set invalidateCache to an update operation, a new cache will be requested by the ResultSet.
      Parameters:
      invalidateCache - new value for invalidateCache
    • setData

      public DSResponse setData(Object data)
      Sets the data to satisfy the DataSource request.

      The object passed to setData() is translated to JavaScript via the JSTranslater class. The expected return data varies by operationType and is described in terms of the JavaScript result (see below) - anything that will be translated to the appropriate JavaScript result is acceptable. Compare all the data formats you can readily retrieve against the capabilities of the JSTranslater. Common options are to pass an XML document fragment or a Collection of Java Beans.

      If the operationType is DataSource.OP_FETCH, then the data is expected to be an Array of JavaScript Objects matching the criteria specified in the DSRequest.

      If the operationType is DataSource.OP_UPDATE, then the data is expected to be a JavaScript Object reflecting the updated record as stored.

      If the operationType is DataSource.OP_ADD, then the data is expected to be a JavaScript Object reflecting the added record as stored.

      If the operationType is DataSource.OP_REMOVE, then the data is expected to be at least the primary key fields of the removed record, an as JavaScript Object. A complete record is also acceptable.

      DSResponses or DSResponse data returned by DMI methods is, by default, automatically filtered to just the set of fields defined on the DataSource. You can override this default in several ways - see the DMI overview in the SmartClient Reference documentation for a full description. For backwards compatibility, non-DMI DSResponses are not filtered in this manner. If you want to enable this filtering for non-DMI responses, you can do so by setting the config parameter DSResponse.dropExtraFields to true in [webroot]/WEB-INF/classes/server.properties. Note that per-DataSource overrides specified by the dropExtraFields setting on the DataSource will still apply in this case. Note that DMI.dropExtraFields and DSResponse.dropExtraFields can be enabled/disabled independently of each other - that is, setting one does not side-effect the other.

      Also, all data objects are automatically filtered through a DataSourceBeanFilter to resolve valueXPaths specified on the DataSource fields. Search the client-side reference for 'valueXPath' for more information on this mechanism.

      Parameters:
      data - the data
      Returns:
      the DSResponse
      See Also:
    • getDataList

      public List getDataList()
      Convenience method to return the data object originally set by setData(), as a List. If the data object is a List, the object is returned; if the data object is a JSONFilter and the wrapped object inside the JSONFilter is a List, the wrapped object is returned. In all other circumstances, this method returns null.
      Returns:
      the data object as originally set by setData(), as a List
      See Also:
    • getDataMap

      public Map getDataMap()
      Convenience method to return the data object originally set by setData(), as a Map. If the data object is a Map, the object is returned; if the data object is actually a List but the first entry in that List is a Map, the first entry in the List is returned. If the data object is a JSONFilter wrapping a Map or a List with a Map in its first entry, this method returns the wrapped Map or the first List entry, as appropriate. In all other circumstances, this method returns null.
      Returns:
      the data object as originally set by setData(), as a Map
      See Also:
    • getData

      public Object getData()
      Returns the data object originally set by setData()
      Returns:
      the data object as originally set by setData()
      See Also:
    • getStartRow

      public long getStartRow()
      Returns the startRow for this DSResponse.
      Returns:
      current value for startRow. If unset, returns -1.
    • setStartRow

      public DSResponse setStartRow(long startRow)
      If the DSRequest specified a startRow, then the DSResponse should return the actual startRow for the response. Note that will not necessarily be the same value as requested. It may be different if the underlying data has changed since the client last made a request.

      Note that startRow and endRow are zero-based - the first record is row zero.

      Parameters:
      startRow - new value for startRow
      Returns:
      the DSResponse
    • getEndRow

      public long getEndRow()
      Returns the endRow for this DSResponse.
      Returns:
      current value for endRow. If unset, returns -1.
    • setEndRow

      public DSResponse setEndRow(long endRow)
      If the DSRequest specified an endRow, then the DSResponse should return the actual endRow for the response. Note that will not necessarily be the same value as requested. It may be different if the underlying data has changed since the client last made a request.

      Note that startRow and endRow are zero-based - the first record is row zero.

      If startRow is currently greater than endRow, it will be reduced to a maximum of endRow (or 0).

      Parameters:
      endRow - new value for endRow
      Returns:
      the DSResponse
    • getTotalRows

      public long getTotalRows()
      Returns the totalRows for this DSResponse.
      Returns:
      current value for totalRows. If unset, returns -1.
    • setTotalRows

      public DSResponse setTotalRows(long totalRows)
      If the DSRequest sent a paged request (see DSRequest.isPaged()) and the total number of records available to be sent to the client given the provided criteria is greater than the requested size, then you should provide the total number of rows that actually matched the provided criteria. This allows the databound component to properly display a visual representation of the portion of the result set actually retrieved.

      For example, the ListGrid uses this value to display a properly sized scrollbar thumb.

      Returns:
      the DSResponse
      See Also:
    • setFailure

      public DSResponse setFailure(String message)
      Sets the status code to BaseResponse.STATUS_FAILURE and provides an error message to be shown to the user.
      Returns:
      the DSResponse
    • getDataSource

      public DataSource getDataSource()
      Returns the currently set DataSource.
      Returns:
      the DataSource associated with this DSResponse
    • setDataSource

      public DSResponse setDataSource(DataSource dataSource)
      Sets the DataSource associated with this DSResponse.
      Parameters:
      dataSource - the datasource to set.
      Returns:
      the DSResponse
    • getRelatedUpdates

      public List getRelatedUpdates()
      Gets list of related updates previously added to this response.
      Returns:
      list of related responses.
      See Also:
    • addRelatedUpdate

      public DSResponse addRelatedUpdate(DSResponse relatedUpdate)
      Causes client-side components to react as though the provided DSResponse had just successfully completed.

      This API can be used to communicate additional changes that occur as a consequence of the current DSResponse succeeding, such as changes to other records in the same DataSource or to records from unrelated DataSources. For example, in CRM applications, Leads may be converted to Accounts. In this case the "remove" operation on the Leads DataSource might call addRelatedUpdate() with a DSResponse representing an "add" operation on the Accounts DataSource. This would cause any client-side caches of Accounts (such as a drop-down list for picking an Account) to automatically update.

      If a DSResponse is passed with the DataSource or operationType unset, they will match the current DSResponse.

      This API can be called multiple times for multiple related updates. Each update is processed by the client-side method DataSource.updateCaches().

      This API should NOT be used simply to complete multiple requests in a single HTTP turnaround, instead, use Queuing for this (see the client-side API isc.RPCManager.startQueue()).

      Parameters:
      relatedUpdate - DSResponse to add.
      Returns:
      the DSResponse that addRelatedUpdate() was called on
    • addRelatedUpdates

      public void addRelatedUpdates(List<DSResponse> relatedUpdates)
      Convenience method that calls addRelatedUpdate(DSResponse) for every entry in the provided List of DSResponse objects
      Parameters:
      relatedUpdates - List of DSResponse objects to add
    • clearRelatedUpdates

      public void clearRelatedUpdates()
      This can be used to clear any automatically-generated related updates
    • getErrorReport

      public ErrorReport getErrorReport()
      Returns the current ErrorReport.
      Returns:
      current ErrorReport
      See Also:
    • setErrorReport

      public DSResponse setErrorReport(ErrorReport errorReport)
      Sets the ErrorReport for this DSResponse
      Parameters:
      errorReport - new errorReport
      Returns:
      the DSResponse
    • addError

      public DSResponse addError(String fieldName, ErrorMessage errorMessage)
      Adds an ErrorMessage to the ErrorReport for this DSResponse. If no ErrorReport exists, one is created. Note that multiple ErrorMessages can be returned for a given field - for example if the field specified multiple validators and more than one those failed.
      Parameters:
      fieldName - the fieldName for the error
      errorMessage - the errorMessage
      Returns:
      the DSResponse
    • addError

      public DSResponse addError(String fieldName, String errorMessage)
      Adds an ErrorMessage to the ErrorReport for this DSResponse. If no ErrorReport exists, one is created. Note that multiple ErrorMessages can be returned for a given field - for example if the field specified multiple validators and more than one those failed.
      Parameters:
      fieldName - the fieldName for the error
      errorMessage - the errorMessage
      Returns:
      the DSResponse
    • getRecord

      public Map<String,Object> getRecord()
      Returns the DSResponse's data member in "record" format (ie, as a nested collection of Maps and Lists that can be directly translated into JSON format by the JSTranslater). Note that this method only works if the DSResponse has had its dataSource member set, either by constructing with a suitable constructor or by calling dsResponse.setDataSource().

      Note: if you want to suppress valueXPath and dropExtraFields, you can call setBypassDataFilter. setDropExtraFields() will likewise be honored.

      Returns:
      This dsResponse's data object, in record format
      See Also:
    • getRecord

      public Map<String,Object> getRecord(DSRequest dsRequest)
      Returns the DSResponse's data member in "record" format (ie, as a nested collection of Maps and Lists that can be directly translated into JSON format by the JSTranslater). Note that this method only works if the DSResponse has had its dataSource member set, either by constructing with a suitable constructor or by calling dsResponse.setDataSource().
      Parameters:
      dsRequest - DSRequest object for context
      Returns:
      This dsResponse's data object, in record format
    • getRecords

      public List getRecords()
      Returns the DSResponse's data member as a list of maps in "record" format (ie, each entry in the list is a nested collection of Maps and Lists that can be directly translated into JSON format by the JSTranslater). Note that this method only works if the DSResponse has had its dataSource member set, either by constructing with a suitable constructor or by calling dsResponse.setDataSource().
      Returns:
      This dsResponse's data object, as a list of maps in record format
    • getRecords

      public List getRecords(DSRequest req)
      Returns the DSResponse's data member as a list of maps in "record" format (ie, each entry in the list is a nested collection of Maps and Lists that can be directly translated into JSON format by the JSTranslater). Note that this method only works if the DSResponse has had its dataSource member set, either by constructing with a suitable constructor or by calling dsResponse.setDataSource().
      Parameters:
      req - DSRequest object for context
      Returns:
      This dsResponse's data object, as a list of maps in record format
    • getRecords

      public List getRecords(ValidationContext vc)
      Returns the DSResponse's data member as a list of maps in "record" format (ie, each entry in the list is a nested collection of Maps and Lists that can be directly translated into JSON format by the JSTranslater). Note that this method only works if the DSResponse has had its dataSource member set, either by constructing with a suitable constructor or by calling dsResponse.setDataSource().
      Parameters:
      vc - Validation context
      Returns:
      This dsResponse's data object, as a list of maps in record format
    • getFieldValue

      public Object getFieldValue(String fieldName)
      Returns the value of the field name provided in this dsResponse's data member. Note that this method first calls getRecord() to obtain a record view of the data.
      Parameters:
      fieldName - The name of the field whose value to return
      Returns:
      The value of the supplied field name in this dsResponse's data member
    • getExportTo

      public OutputStream getExportTo()
      Returns the OuputStream we will use for data export. If you have not set this explicitly with the setExportTo(OutputStream) API, it will be null.
      Returns:
      The export OutputStream
    • setExportTo

      public DSResponse setExportTo(OutputStream exportOutputStream)
      Sets the OuputStream we will use for data export (this means exports to CSV, XML, JSON and Excel formats; PDF exports are "content exports" and are different). This API allows you to arrange for other export scenarios than the two built-in options (download to client and write to filesystem). If you set this property, it overrides the default OutputStream we would normally create for a filesystem export; in other words, we will export to your OutputStream rather than to a filesystem file.
      Parameters:
      exportOutputStream - An OutputStream to use for the export
      Returns:
      The DSResponse itself
    • getExportObject

      public Object getExportObject(DSRequest dsRequest) throws Exception
      Returns the Java object encapsulating the exported data in a format suitable for directly loading into Microsoft Excel. Note that calling this method causes the parameter dsRequest to be executed inline, if it has not already been executed, in order to fetch and format the data. Note that this API is only applicable when the parameter DSRequest is for an export to XLS or OOXML format.

      Currently, we use the Apache POI library to perform Excel exports, so the object returned by this method will be an instance of that library's Workbook interface.

      Use this API with extreme caution. Most of its behavior is subject to change without notice. The types of objects returned by this API may be changed in future versions without notice if the Server Framework begins using a newer version of the various libraries used for exports (eg a newer version of Apache POI) and could change to a completely different type if the Server Framework switches to using a different library for a given type of export.

      Further, the contents of the export object are likewise subject to change without notice, including, for example, the specific way that type, formatting and styling information is conveyed to Excel.

      If you choose to use this API, when interacting with the generated export object, code defensively and rely on as few specifics as possible. Also, be sure to revisit and re-test this code when upgrading to new versions of the Server Framework.

      Parameters:
      dsRequest - The DSRequest to execute to obtain the export object
      Returns:
      The export object
      Throws:
      Exception
    • setExportObject

      public DSResponse setExportObject(Object exportObject) throws Exception
      Set the export object on the DSResponse. Note that this API is only applicable when the parameter DSRequest is for an export to XLS or OOXML format. Calling this method causes the server framework to use the provided object rather than running through the export process.

      Currently, we use the Apache POI library to perform Excel exports, so the object provided to this method must be an instance of that library's Workbook interface.

      Use this API with extreme caution. Most of its behavior is subject to change without notice. The types of object accepted by this API may be changed in future versions without notice if the Server Framework begins using a newer version of the various libraries used for exports (eg a newer version of Apache POI) and could change to a completely different type if the Server Framework switches to using a different library for a given type of export.

      Parameters:
      exportObject - The export object to associate with this DSResponse
      Returns:
      The DSResponse itself
      Throws:
      Exception
    • hasNextRecord

      public boolean hasNextRecord()
      This method is called by the framework during streaming. If you are using SQLDataSource, the default implementation will return the correct value. Otherwise, you must override this method and cause it to return an appropriate value for the current dataset. The approach we recommend is to convert your DSResponse's data member to an StreamingResponseIterator and then override hasNextRecord() and nextRecordAsObject() on the DSResponse to return appropriate values. For example:
         public DSResponse dmiMethod(DSRequest dsRequest) {
             List data = (List)dsRequest.execute().getData();
             CustomDSResponse resp = new CustomDSResponse();
             resp.setUnderlyingIterator(data.iterator());
             resp.setData(new StreamingResponseIterator(resp));
             return resp;
         }
         
         static class CustomDSResponse extends DSResponse {
      
             private Iterator underlyingIterator;
             public void setUnderlyingIterator(Iterator it) {
                 underlyingIterator = it;
             }
      
             public CustomDSResponse(DataSource dataSource) {
                 super(dataSource);
             }
             public boolean hasNextRecord() {
                 return underlyingIterator.hasNext();
             }
             public Object nextRecordAsObject() throws StreamingResponseException {
                 return underlyingIterator.next();
             }
         }
       
      Note, this method is only applicable when streaming a response.
      Returns:
      true if there is at least one more record to read
      See Also:
    • nextRecordAsObject

      public Object nextRecordAsObject() throws com.isomorphic.datasource.StreamingResponseException
      This method is called by the framework during streaming. If you are using SQLDataSource, the default implementation will return the next available row, as you would expect. Otherwise, you must override this method and cause it to return the next row. If you do not know upfront how many rows there are in your dataset, you can also increment endRow in this method, so that the client ends up with an accurate rowcount. For example:
         public Object nextRecordAsObject() throws StreamingResponseException {
             Object obj = someUserMethodToGetTheNextRecord();
             if (obj != null) {
                 this.setEndRow(this.getEndRow() + 1);
             }
             return obj;
         }
       
      Note, this method is only applicable when streaming a response.
      Returns:
      the next record as an instance of Object
      Throws:
      com.isomorphic.datasource.StreamingResponseException
      See Also:
    • setProgressiveLoading

      public void setProgressiveLoading(boolean value)
      Mark this dsResponse as having progressiveLoading enabled. In this mode, the totalRows attribute of the response is intended to be a valid lower-bound
    • setEstimatedTotalRows

      public DSResponse setEstimatedTotalRows(String estimatedTotalRows)
      For fetch requests where progressiveLoading is enabled, dsResponse.estimatedTotalRows may be set to indicate the true size of the data set.

      This value may be set to a String in the following format:

      • "500+": There are at least 500 records
      • "-500": There are fewer than 500 records
      • "450-500": There are between 450 and 500 records
      • "~500": There are approximately 500 records
      • "500": There are exactly than 500 records
      This property will be set automatically to an exact value if a row count query was performed and the result exceeded the progressiveLoadingThreshold (where supported), causing progressiveLoading to be enabled.
      See Also:
    • getKeys

      public Map getKeys()
      For responses produced by SQLDataSource and subclasses only, this method returns the Map of key values used in the SQL query. It includes any keys that were generated by the database for "add" operations (though note there are some provisos - see the client-side documentation for "makeKeysAvailable").

      The motivation for providing this API is to allow user-written code to provide data for cache-synchronization purposes, in rare edge cases where the framework's automatic cache-sync processing causes problems (for example, record deadlocks in complex scenarios involving queues of updates to multiple different DataSources). The intention is that you mark your operationBinding canSyncCache="false" and then use the getKeys() API in your own logic.

      Returns:
      the Map of key values used