com.isomorphic.datasource

## Class DSTransaction

- java.lang.Object
- - com.isomorphic.datasource.DSTransaction

-     public class DSTransaction
      extends java.lang.Object

  Manages a transaction that involves multiple `DSRequest` or `RPCRequest` objects.

  DSTransaction tracks a queue of requests and provides APIs for commiting, rolling back, managing error status, freeing resources, and enabling features like "Transaction Chaining" (see client-side docs).

  For an overview of usage, see the client-side documentation overview "Standalone DataSource Usage".

- - ### Method Summary

    All Methods Instance Methods Concrete Methods
    Modifier and Type | Method and Description
    --- | ---
    `void` | `addToScriptContext(java.lang.String name, java.lang.Object value)` If you're using any of the script-based, server-side request or response transformation features - `transformRequestScript`, `transformResponseScript` or `fieldValueScript` - you can make additional Java objects available to the script for every request in the current queue by calling this method.
    `void` | `addToTemplateContext(java.lang.Object key, java.lang.Object value)` Same as the `three-argument version`, but the third argument (isSnippet) is always false.
    `void` | `addToTemplateContext(java.lang.String name, java.lang.Object value, boolean isSnippet)` Adds an attribute to the template context which makes it available when using Velocity templates.
    `void` | `applyEarlierResponseValues(DSRequest dsRequest)` Applies values from earlier responses in this transaction to the supplied DSRequest, in accordance with the and tags on the DSRequest's operationBinding.
    `void` | `commit()` Commits the current transaction.
    `void` | `complete()` Commits or rolls back the current transaction and frees the DSTransaction's resources.
    `BaseResponse` | `findFirstResponse(java.lang.String dsName, java.lang.String opType)` Returns the `response` for the first request where the DataSource and operation type match the parameter values (null parameters match any DataSource / operation type).
    `BaseResponse` | `findLastResponse(java.lang.String dsName, java.lang.String opType)` Returns the `response` for the request most immediately prior to the current request, where the DataSource and operation type match the parameter values.
    `void` | `freeAllResources()` Frees all shared resources (for example, DataSource instances and database connections) used by this DSTransaction, including any DSRequest-level resources that have not already been freed automatically at the end of request processing.
    `void` | `freeQueueResources()` Frees shared resources (for example, DataSource instances and database connections) used by this DSTransaction and associated with the overall queue, as opposed to a particular DSRequest within that queue.
    `java.lang.Boolean` | `getAuthenticated()` Returns true if we have an authenticated user for this request.
    `DataSource` | `getDataSource(java.lang.String dsName)` Returns an instance of the DataSource named in the "dsName" parameter.
    `java.util.Set` | `getRequests()` Returns a list of the requests that are registered with this transaction.
    `BaseResponse` | `getResponse(BaseRequest baseRequest)` Retrieves a response for a specific request which has been registered with this transaction.
    `int` | `getTransactionPolicy()` Gets the TransactionPolicy currently in place for this transaction.
    `java.lang.String` | `getUserId()` Returns the user ID associated with the queue of requests being managed by this RPCManager.
    `java.util.List` | `getUserRoles()` Returns a list of the roles associated with the user who is authenticated for this request.
    `java.lang.Boolean` | `isClientRequest()` Returns this transactions default value for clientRequest.
    `boolean` | `isSkipRemainingQueue()` Check if the remaining requests in the queue will be skipped.
    `java.util.Map` | `processQueue()` Mainly for standalone usage of DSTransaction, this method will go through each request that has been registered with the DSTransaction and pass it to the request handler.
    `java.util.Map` | `processQueue(BaseRequestHandler requestHandler)` Mainly for standalone usage of DSTransaction, this method will go through each request that has been registered with the DSTransaction and pass it to the request handler.
    `boolean` | `queueHasFailures()` Returns true if any request in the current queue failed.
    `void` | `registerRequest(BaseRequest request)` Registers a request with the transaction.
    `void` | `registerResponse(BaseRequest request, BaseResponse response)` Registers a response for a request with the transaction.
    `void` | `rollback()` Rolls back the current transaction.
    `void` | `setAuthenticated(boolean authenticated)` Pass true to this method to indicate that every request in the queue is associated with an authenticated user.
    `void` | `setClientRequest(java.lang.Boolean clientRequest)` Sets the default clientRequest value for any request included in this transaction.
    `void` | `setTransactionPolicy(int transactionPolicy)` Sets the `TransactionPolicy` to use for this transaction, by default this will be fetched from server.properties "RPCManager.transactionPolicy" and if not found will be NOT_SET.
    `void` | `setUserId(java.lang.String userId)` Set the user ID associated with the queue of requests being managed by this RPCManager.
    `void` | `setUserRoles(java.util.List rolesList)` Accepts a List of roles associated with the user who is authenticated for this request.
    `void` | `setUserRoles(java.lang.String rolesString)` Accepts a comma-separated String representing the list of roles associated with the user who is authenticated for this request.
    `void` | `setUserRoles(java.lang.String[] roles)` Accepts a List of roles associated with the user who is authenticated for this request.
    `void` | `skipRemainingQueue()` Calling this tells the `DSTransaction` that all the remaining requests in the queue should be skipped.

- - ### Method Detail

    - #### queueHasFailures

          public boolean queueHasFailures()

      Returns true if any request in the current queue failed. This method can be used by user code to avoid processing later operations if earlier ones have failed.

    - #### skipRemainingQueue

          public void skipRemainingQueue()

      Calling this tells the `DSTransaction` that all the remaining requests in the queue should be skipped. Those requests will instead return a response with a status of `BaseResponse.STATUS_PROCESSING_SKIPPED`.

      This ensures that the remaining requests don't actually do any logic processing. A typical use-case for this is when you manually handle a transaction queue and after executing a request, use `DSTransaction.queueHasFailures()` to check if there is a failure, you can tell the remaining queue to skip processing, giving you consistent responses for those requests that were skipped.

    - #### isSkipRemainingQueue

          public boolean isSkipRemainingQueue()

      Check if the remaining requests in the queue will be skipped.
      Returns:
        true if the remaining requests in the queue will be skipped.

    - #### registerRequest

          public void registerRequest(BaseRequest request)

      Registers a request with the transaction.
      Parameters:
        `request` - the request to add to the transaction.

    - #### registerResponse

          public void registerResponse(BaseRequest request,
                                       BaseResponse response)

      Registers a response for a request with the transaction.
      Parameters:
        `request` - the request for which the response belongs to.
        `response` - the response.

    - #### getRequests

          public java.util.Set getRequests()

      Returns a list of the requests that are registered with this transaction.
      Returns:
        list of requests.

    - #### commit

          public void commit()
                      throws java.lang.Exception

      Commits the current transaction.

      Typically, there is no need to commit manually because it is done automatically when you call `DSTransaction.complete()`, if all the DSRequests associated with this DSTransaction completed successfully. Therefore, this method is only necessary if you elect to manually manage the transaction. Note, this method does not free the database connection, so if you do manage the transaction manually, you are responsible for freeing resources - see `DSTransaction.freeQueueResources()`.

      In general, use this API only if you are sure you have a good reason for not using `complete()`.
      Throws:
        `java.lang.Exception`

    - #### rollback

          public void rollback()
                        throws java.lang.Exception

      Rolls back the current transaction.

      Typically, there is no need to rollback manually because it is done automatically when you call `DSTransaction.complete()`, if one or more of the DSRequests associated with this DSTransaction failed. Therefore, this method is only necessary if you elect to manually manage the transaction. Note, this method does not free the database connection, so if you do manage the transaction manually, you are responsible for freeing resources - see `DSTransaction.freeQueueResources()`.

      In general, use this API only if you are sure you have a good reason for not using `complete()`.
      Throws:
        `java.lang.Exception`

    - #### getTransactionPolicy

          public int getTransactionPolicy()

      Gets the TransactionPolicy currently in place for this transaction.
      Returns:
        the transaction policy.

    - #### setTransactionPolicy

          public void setTransactionPolicy(int transactionPolicy)
                                    throws QueueAlreadyStartedException

      Sets the `TransactionPolicy` to use for this transaction, by default this will be fetched from server.properties "RPCManager.transactionPolicy" and if not found will be NOT_SET.
      Parameters:
        `transactionPolicy` - the transaction policy to set.
      Throws:
        `QueueAlreadyStartedException`

    - #### complete

          public void complete()

      Commits or rolls back the current transaction and frees the DSTransaction's resources. This API is the one normally used to complete and clean up a DSTransaction when all the associated DSRequests have been executed.

      If all the DSRequests associated with this DSTransaction completed successfully, this method commits the transaction; otherwise, it rolls the transaction back. Either way, resources are freed (see `DSTransaction.freeQueueResources()`).

    - #### freeQueueResources

          public void freeQueueResources()

      Frees shared resources (for example, DataSource instances and database connections) used by this DSTransaction and associated with the overall queue, as opposed to a particular DSRequest within that queue. DSRequest-level resources are freed automatically at the end of request processing unless the request is not marked `freeOnExecute`, in which case its resources are considered to be queue-level resources and will be freed by this method. If you have a need to free all resources associated with a DSTransaction, see `DSTransaction.freeAllResources()`.

      Note, any DSRequest targeting @link{com.isomorphic.hibernate.HibernateDataSource} or `JPADataSource` is `freeOnExecute:false` by default in order to allow traversing lazy entity associations.

      Typically, there is no need to free resources manually because it is done automatically when you call `DSTransaction.complete()`. Therefore, this method is only necessary if you elect to manually manage the transaction by calling `DSTransaction.commit()` or `DSTransaction.rollback()` instead of `complete()`.

      Note that the resources freed by this API are made immediately available to other threads: do not cache DataSource instances or other resources and attempt to reuse them after calling this API. In general, use this API only if you are sure you have to.

    - #### freeAllResources

          public void freeAllResources()

      Frees all shared resources (for example, DataSource instances and database connections) used by this DSTransaction, including any DSRequest-level resources that have not already been freed automatically at the end of request processing. See also `DSTransaction.freeQueueResources()`.

      Typically, there is no need to free resources manually because it is done automatically when you call `DSTransaction.complete()`. Therefore, this method is only necessary if you elect to manually manage the transaction by calling `DSTransaction.commit()` or `DSTransaction.rollback()` instead of `complete()`.

      Note that the resources freed by this API are made immediately available to other threads: do not cache DataSource instances or other resources and attempt to reuse them after calling this API. In general, use this API only if you are sure you have to.

    - #### getResponse

          public BaseResponse getResponse(BaseRequest baseRequest)

      Retrieves a response for a specific request which has been registered with this transaction.
      Parameters:
        `baseRequest` - the request for which to get the response.
      Returns:
        the response, either RPCResponse or DSResponse but can also be referenced using the abstract class BaseResponse.

    - #### processQueue

          public java.util.Map processQueue()

      Mainly for standalone usage of DSTransaction, this method will go through each request that has been registered with the DSTransaction and pass it to the request handler.

      The handling of how requests are executed and how errors should be handled can be customised by creating an implementation of `BaseRequestHandler` and setting it on the DSTransaction.

      NOTE: this feature is supported only in Power Edition or above.

      Returns:
        a map of requests and responses so that the calling code can get access to these after processing.

    - #### processQueue

          public java.util.Map processQueue(BaseRequestHandler requestHandler)

      Mainly for standalone usage of DSTransaction, this method will go through each request that has been registered with the DSTransaction and pass it to the request handler.

      The handling of how requests are executed and how errors should be handled can be customised by creating an implementation of `BaseRequestHandler` and setting it on the DSTransaction.

      NOTE: this feature is supported only in Power Edition or above.

      Parameters:
        `requestHandler` - a custom request handler which will deal with individual request execution and error handling.
      Returns:
        a map of requests and responses so that the calling code can get access to these after processing.

    - #### applyEarlierResponseValues

          public void applyEarlierResponseValues(DSRequest dsRequest)
                                          throws java.lang.Exception

      Applies values from earlier responses in this transaction to the supplied DSRequest, in accordance with the and tags on the DSRequest's operationBinding. We call this process "Transaction Chaining". See the client-side OperationBinding documentation for details.
      Parameters:
        `dsRequest` - The DSRequest to apply values to
      Throws:
        `java.lang.Exception`

    - #### findLastResponse

          public BaseResponse findLastResponse(java.lang.String dsName,
                                               java.lang.String opType)

      Returns the `response` for the request most immediately prior to the current request, where the DataSource and operation type match the parameter values. For example:

             DSResponse resp = dsTransaction.findLastResponse("customer", "update");

      would return the response to the most recent update request on the "customer" DataSource prior to the request currently being processed (ie, the first one in the queue with no response)

      This method is just one way to access the response to a request earlier in the queue - it is a programmatic equivalent of using `$responseData.last()` in a Velocity expression. Scan the client-side documentation for "transaction chaining" for a full discussion of the various options available when using the Transaction Chaining approach.

      Parameters:
        `dsName` - The name of the DataSource to find a response for (null means any DataSource)
        `opType` - The operation type to find a response for (null means any operation type)
      Returns:
        the DSResponse matching the search criteria

    - #### findFirstResponse

          public BaseResponse findFirstResponse(java.lang.String dsName,
                                                java.lang.String opType)

      Returns the `response` for the first request where the DataSource and operation type match the parameter values (null parameters match any DataSource / operation type). For example:

             DSResponse resp = dsTransaction.findFirstResponse("customer", "update");

           would return the response to the first update request on the "customer" DataSource.

           This method is just one way to access the response to a request earlier in the queue -
           it is a programmatic equivalent of using $responseData.first() in a Velocity
           expression.  Scan the client-side documentation for "transaction chaining" for a full
           discussion of the various options available when using the Transaction Chaining approach.

      Parameters:
        `dsName` - The name of the DataSource to find a response for (null means any DataSource)
        `opType` - The operation type to find a response for (null means any operation type)
      Returns:
        the DSResponse matching the search criteria

    - #### addToTemplateContext

          public void addToTemplateContext(java.lang.Object key,
                                           java.lang.Object value)

      Same as the `three-argument version`, but the third argument (isSnippet) is always false.
      Parameters:
        `key` - the attribute key.
        `value` - the attribute value, this can be a fully nested Java object.

    - #### addToTemplateContext

          public void addToTemplateContext(java.lang.String name,
                                           java.lang.Object value,
                                           boolean isSnippet)

      Adds an attribute to the template context which makes it available when using Velocity templates.

      The `isSnippet` parameter controls whether the framework treats the context object as a regular context variable, or a user-defined snippet of text. If isSnippet is true, the context object will be evaluated through Velocity immediately prior to the main Velocity evaluation taking place. This means that you can create context variables that themselves contain variable references, and those references will be correctly resolved in the final output. Read the "User-defined snippets" section of the "customQuerying" article in the client-side docs for more details.

      Note, context variables added via this method will be overridden by context variables of the same name added via the com.isomorphic.datasource.DSRequest#addToTemplateContext(java.lang.Object, java.lang.Object, boolean) DSRequest.addToTemplateContext() method}

      Parameters:
        `name` - the name of the new object as it should appear in the Velocity namespace
        `value` - arbitrary Java object
        `isSnippet` - Is the context object a user-defined snippet?

    - #### addToScriptContext

          public void addToScriptContext(java.lang.String name,
                                         java.lang.Object value)

      If you're using any of the script-based, server-side request or response transformation features - `transformRequestScript`, `transformResponseScript` or `fieldValueScript` - you can make additional Java objects available to the script for every request in the current queue by calling this method. To make objects available to just a single request, see `DSRequest.addToScriptContext()`

      For example, set up a string in Java code:

               dsRequest.getDsTransaction().addToScriptContext("mySimpleString", "This is a test");

      and then use that string in your transformation script:

               <DataSource ID="myDS">
                   <transformResponseScript language="groovy">
                       // Add a property to the response object
                       responseObject["testingTransform"] = mySimpleString;
                       . . .
                   </transformResponseScript>
                   . . .
               </DataSource>

      Parameters:
        `name` - the name of the new object as it should be made available to the script
        `value` - arbitrary Java object

    - #### getDataSource

          public DataSource getDataSource(java.lang.String dsName)
                                   throws java.lang.Exception

      Returns an instance of the DataSource named in the "dsName" parameter. This method borrows an object from the framework's DataSource pool and records it for release with this transaction. It is the recommended way to obtain an arbitrary DataSource object in your own server-side code. Note that this method is intended for use if you need to obtain some arbitrary DataSource. If what you want is the DataSource associated with the current DSRequest (a common use case), use `DSRequest.getDataSource()` instead. Also, if you are trying to access some arbitrary DataSource purely because you need to run a DSRequest on it (another very common use case), consider just creating the DSRequest instead, using one of the constructors that accepts a DataSource name. DataSources obtained through this method are released by `DSTransaction.freeDataSources()`, `DSTransaction.freeQueueResources()`, or `DSTransaction.freeAllResources()`. You may call `freeDataSources()` earlier if you are finished with every DataSource obtained through this transaction since its previous call.
      Parameters:
        `dsName` - The name of the DataSource to return
      Throws:
        `java.lang.Exception`
      See Also:
        `DSRequest.getDataSource()`, `DSRequest(java.util.Map, com.isomorphic.servlet.RequestContext, com.isomorphic.rpc.RPCManager)`

    - #### setUserId

          public void setUserId(java.lang.String userId)

      Set the user ID associated with the queue of requests being managed by this RPCManager. This value will be used by the framework to populate fields of types "creator" and "modifier". This API is intended for use when you are a using some custom authentication scheme - it is unnecessary if you are using the Servlet API for authentication, because we will default to using the value returned by `HttpServletRequest.getRemoteUser()`.

      Calling this API automatically sets the authentication status of the RPCManager. If you pass a non-null value, the authentication status is set to true. If you pass null, the authentication status is also set to null.

      Parameters:
        `userId` - The user ID to associate with the queue of requests being managed by this RPCManager
      See Also:
        `RPCManager.getUserId()`, `RPCManager.setAuthenticated(boolean)`

    - #### getUserId

          public java.lang.String getUserId()

      Returns the user ID associated with the queue of requests being managed by this RPCManager. This value can be set by the `RPCManager.setUserId(String)`; if that method has not been called and we are running in the context of the servlet API, we call the servlet API's `getRemoteUser()` method.
      Returns:
        The user ID associated with the queue of requests being managed by this RPCManager, or null if there is no authenticated user
      See Also:
        `RPCManager.setUserId(String)`

    - #### getAuthenticated

          public java.lang.Boolean getAuthenticated()

      Returns true if we have an authenticated user for this request. Please see the client-side documentation for DataSource.requiresAuthentication/ for details of how the authentication system works
      Returns:
        true if we have an authenticated user, otherwise false
      See Also:
        `RPCManager.setAuthenticated(boolean)`

    - #### setAuthenticated

          public void setAuthenticated(boolean authenticated)

      Pass true to this method to indicate that every request in the queue is associated with an authenticated user. You will need to do this if you wish to implement an authentication that is not based on the scheme built in to the servlet API. Please see the client-side documentation for DataSource.requiresAuthentication for details of how the authentication system works
      Parameters:
        `authenticated` - if true we have an authenticated user
      See Also:
        `RPCManager.getAuthenticated()`, `RPCManager.setUserRoles(String)`, `RPCManager.setUserRoles(java.util.List)`

    - #### getUserRoles

          public java.util.List getUserRoles()

      Returns a list of the roles associated with the user who is authenticated for this request. Note that this list must be manually populated by calling setUserRoles(); it is an alternative mechanism, in case you wish to implement a role-based security system other than the one built into the servlet API. Please see the client-side documentation for OperationBinding.requiresRole for details of how the authentication/security system works
      Returns:
        The list of roles associated with the currently authenticated user, or null if no such list has been set up
      See Also:
        `RPCManager.getAuthenticated()`, `RPCManager.setUserRoles(java.util.List)`, `RPCManager.setUserRoles(String)`

    - #### setUserRoles

          public void setUserRoles(java.lang.String rolesString)

      Accepts a comma-separated String representing the list of roles associated with the user who is authenticated for this request. This method allows you to implement a role-based security system other than the one built in to the servlet API. Please see the client-side documentation for OperationBinding.requiresRole for details of how the authentication/security system works
      Parameters:
        `rolesString` - A comma-separated String representing the list of roles associated with the authenticated user
      See Also:
        `RPCManager.setAuthenticated(boolean)`, `RPCManager.getUserRoles()`

    - #### setUserRoles

          public void setUserRoles(java.lang.String[] roles)

      Accepts a List of roles associated with the user who is authenticated for this request.

      This method allows you to implement a role-based security system other than the one built in to the servlet API. Please see the client-side documentation for OperationBinding.requiresRole for details of how the authentication/security system works

      Parameters:
        `roles` - The list of roles associated with the authenticated user
      See Also:
        `RPCManager.setAuthenticated(boolean)`, `RPCManager.getUserRoles()`

    - #### setUserRoles

          public void setUserRoles(java.util.List rolesList)

      Accepts a List of roles associated with the user who is authenticated for this request.

      This method allows you to implement a role-based security system other than the one built in to the servlet API. Please see the client-side documentation for OperationBinding.requiresRole for details of how the authentication/security system works

      Parameters:
        `rolesList` - The list of roles associated with the authenticated user
      See Also:
        `RPCManager.setAuthenticated(boolean)`, `RPCManager.getUserRoles()`

    - #### isClientRequest

          public java.lang.Boolean isClientRequest()

      Returns this transactions default value for clientRequest.
      Returns:
        true if default value is set to true, otherwise false.

    - #### setClientRequest

          public void setClientRequest(java.lang.Boolean clientRequest)

      Sets the default clientRequest value for any request included in this transaction. If set to true, this will enabled declarative security checks for all requests in this transaction.
      Parameters:
        `clientRequest` - true if this is a clientRequest transaction.
      See Also:
        `BaseRequest.setClientRequest(Boolean)`