Class DSTransaction

java.lang.Object
com.isomorphic.datasource.DSTransaction
All Implemented Interfaces:
com.isomorphic.datasource.DSCacheManager

public class DSTransaction extends Object implements com.isomorphic.datasource.DSCacheManager
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

    Modifier and Type
    Method
    Description
    void
    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
    Same as the three-argument version, but the third argument (isSnippet) is always false.
    void
    addToTemplateContext(String name, Object value, boolean isSnippet)
    Adds an attribute to the template context which makes it available when using Velocity templates.
    void
    Applies values from earlier responses in this transaction to the supplied DSRequest, in accordance with the and tags on the DSRequest's operationBinding.
    void
    Commits the current transaction.
    void
    Commits or rolls back the current transaction and frees the DSTransaction's resources.
    <T extends BaseResponse>
    T
    findFirstResponse(String dsName, 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).
    <T extends BaseResponse>
    T
    findLastResponse(String dsName, 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
    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
    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.
    Returns true if we have an authenticated user for this request.
    Returns an instance of the DataSource named in the "dsName" parameter.
    Returns a list of the requests that are registered with this transaction.
    <T extends BaseResponse>
    T
    getResponse(BaseRequest baseRequest)
    Retrieves a response for a specific request which has been registered with this transaction.
    Returns the tenant ID associated with the queue of requests for this transaction.
    int
    Gets the TransactionPolicy currently in place for this transaction.
    Returns the user ID associated with the queue of requests being managed by this RPCManager.
    Returns a list of the roles associated with the user who is authenticated for this request.
    Returns this transactions default value for clientRequest.
    boolean
    Check if the remaining requests in the queue will be skipped.
    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.
    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
    Returns true if any request in the current queue failed.
    void
    Registers a request with the transaction.
    void
    Registers a response for a request with the transaction.
    void
    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(Boolean clientRequest)
    Sets the default clientRequest value for any request included in this transaction.
    void
    setTenantId(String tenantId)
    Set the tenant ID associated with the queue of requests for 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(String userId)
    Set the user ID associated with the queue of requests being managed by this RPCManager.
    void
    setUserRoles(String rolesString)
    Accepts a comma-separated String representing the list of roles associated with the user who is authenticated for this request.
    void
    setUserRoles(String... roles)
    Accepts a List of roles associated with the user who is authenticated for this request.
    void
    setUserRoles(List<String> rolesList)
    Accepts a List of roles associated with the user who is authenticated for this request.
    void
    Calling this tells the DSTransaction that all the remaining requests in the queue should be skipped.
  • Method Details

    • 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 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 Set<BaseRequest> getRequests()
      Returns a list of the requests that are registered with this transaction.
      Returns:
      list of requests.
    • commit

      public void commit() throws Exception
      Commits the current transaction.

      Typically, there is no need to commit manually because it is done automatically when you call 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 freeQueueResources().

      In general, use this API only if you are sure you have a good reason for not using complete().

      Throws:
      Exception
    • rollback

      public void rollback() throws Exception
      Rolls back the current transaction.

      Typically, there is no need to rollback manually because it is done automatically when you call 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 freeQueueResources().

      In general, use this API only if you are sure you have a good reason for not using complete().

      Throws:
      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 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 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 complete(). Therefore, this method is only necessary if you elect to manually manage the transaction by calling commit() or 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 freeQueueResources().

      Typically, there is no need to free resources manually because it is done automatically when you call complete(). Therefore, this method is only necessary if you elect to manually manage the transaction by calling commit() or 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 <T extends BaseResponse> T 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 Map<BaseRequest,BaseResponse> 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 Map<BaseRequest,BaseResponse> 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 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:
      Exception
    • findLastResponse

      public <T extends BaseResponse> T findLastResponse(String dsName, 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 <T extends BaseResponse> T findFirstResponse(String dsName, 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(Object key, 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(String name, 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(String name, 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(String dsName) throws Exception
      Returns an instance of the DataSource named in the "dsName" parameter. This method borrows an object from the framework's DataSource pool, and ensures that it is freed at the end of the request cycle. 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. If you still end up using this method you must make sure you call freeDataSources() when you are finished, otherwise the DataSources will still be lingering around and become unavailable for anything else that might need them inevitably causing a memory leak.
      Parameters:
      dsName - The name of the DataSource to return
      Throws:
      Exception
      See Also:
    • setUserId

      public void setUserId(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:
    • getUserId

      public 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:
    • setTenantId

      public void setTenantId(String tenantId)
      Set the tenant ID associated with the queue of requests for this transaction.
      Parameters:
      tenantId - Tenant ID to associate with the queue of requests for this transaction
      See Also:
    • getTenantId

      public String getTenantId()
      Returns the tenant ID associated with the queue of requests for this transaction.
      Returns:
      the renant ID associated with the queue of requests for this transaction
      See Also:
    • getAuthenticated

      public 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:
    • 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:
    • getUserRoles

      public List<String> 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:
    • setUserRoles

      public void setUserRoles(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:
    • setUserRoles

      public void setUserRoles(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:
    • setUserRoles

      public void setUserRoles(List<String> 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:
    • isClientRequest

      public Boolean isClientRequest()
      Returns this transactions default value for clientRequest.
      Returns:
      true if default value is set to true, otherwise false.
    • setClientRequest

      public void setClientRequest(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: