PDF version
RESTful transactions
Introduction
Since version 0.4 Gomba implements RESTful (or simply HTTP) transactions. A client may start a transaction by POSTing on a URL mapped to org.gomba.TransactionServlet. TransactionSerrvlet responds with 201 (Created) status code and the Location header set to the path where the new transaction has been created, as defined by the HTTP spec. By GETting this URL the client obtains an XML representation of the transaction. Something like this:
<transaction>
<uri>http://domain/myService/transactions/D29271F549AFF9889647883591248B53</uri>
<lastAccessed>2005-01-25T12:12:56</lastAccessed>
</transaction>
At this point the client can use the transation URI to mark further requests belonging to that transaction. This can be done by adding the transaction URI to a HTTP header, a query string parameter or anything else that makes sense.
When the client is done, the transaction is committed by PUTting an empty resource on the transaction URI. If something went wrong the client must DELETE on the transaction URI in order to rollback the transaction. If the client fails to do so, TransactionServlet will garbage collect the transaction once it has expired and log client's bad behaviour.
Configuration
This tells TransactionServlet where to get the transaction identifier in order to associate a request to a transaction.
<!-- Default transaction URI for Gomba servlets -->
<context-param>
<param-name>org.gomba.transactionURI</param-name>
<param-value>${header.X-Transaction-URI}</param-value>
</context-param>
This configures the TransactionServlet:
<!-- TransactionServlet -->
<servlet>
<servlet-name>transaction</servlet-name>
<servlet-class>org.gomba.TransactionServlet</servlet-class>
<init-param>
<param-name>transaction-id</param-name>
<param-value>${path.0}</param-value>
</init-param>
<init-param>
<param-name>transaction-uri</param-name>
<param-value>&uri-space;transactions/${transaction.id}</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Finally, this maps HTTP requests to the TransactionServlet:
<!-- TransactionServlet -->
<servlet-mapping>
<servlet-name>transaction</servlet-name>
<url-pattern>/transactions/*</url-pattern>
</servlet-mapping>
Scalability
TransactionServlet maintains the state of the transaction in memory. When running multiple servlet engine instances (i.e. in a production environment) you need ensure that once a client started a transaction, further requests will be served by the same instance that started the transaction. The jvm-route option comes to the rescue. It works by appending a unique server identifier to the transaction id. Something like this:
D29271F549AFF9889647883591248B53.myserver
If you are using the popular Apache HTTPD server, mod-rewrite can help balancing the servlet engine instances:
# requests that are part of a transaction
RewriteCond %{HTTP:X-Transaction-URI} .*\.(.*)
RewriteRule ^/mywebservice/(.*) http://%1.myhost:8080$0 [P]
# requests to the TransactionServlet: start, commit, rollback
RewriteRule ^/mywebservice/transactions/.*\.(.*) http://$1.myhost:8080$0 [P]