Policy allows you to control the runtime behavior of a service in a declarative manner, independent of the service implementation and binding details. For example, you may require that a service always participates in a global transaction. One way to achieve this would be to add logic to your service implementation which checks the current transaction state, associates with an active global transaction, and handles error cases such as when a global transaction does not exist. Of course, this pollutes your application logic with runtime details and also makes the service implementation less flexible - any time you want to change the transactional behavior, you have to change the service implementation. Another way to satisfy the transaction policy would be to ensure that the gateway used to expose the service is transactional and that it propagates the transaction to the service implementation. The problem with this approach is that there is no explicit constraint defined for transactionality, so if the binding configuration changes between environments or the service is repackaged into another application, you could unintentionally violate your constraint that the service must participate in a global transaction. Policy support addresses this problem by allowing you to express these requirements in your application configuration outside of the service implementation and binding configuration. These policy definitions are picked up by the runtime during deployment and enforced on a per-message basis as services are invoked.
There are two aspects to a Policy definition:
- What policy does the service provider require?
- What policy support does the service consumer provide?
You define the policy that a service requires by annotating the service's configuration in the SwitchYard application descriptor. You also define how a service is consumed (e.g. through a gateway binding), which effectively determines how the policy requirements are satisfied (or provided). The runtime will take care of determining whether the consumer satisfies the policy requirements by evaluating the configuration of the application and the runtime state of the messages exchanged between the consumer and provider.
Take the following example configuration:
The service has declared that it requires a global transaction by including the requires attribute with a value of "propagatesTransaction". This service is available at two distinct JMS endpoints - one is configured to provide a transaction (policyQSTransacted) and the other is not (policyQSNonTransacted). When messages are sent to the policyQSTransacted queue, the service is invoked in the context of a global transaction. When messages are sent to the policyQSNonTransacted queue, the SwitchYard runtime rejects the message because it violates the policy requirements of the service (there is no transaction).
|The provided policy is actually set at runtime by the Camel component in this scenario. An alternate option that is not yet implemented would allow the provided policy to be directly set on the binding in the configuration. Each component would be responsible for interpreting this policy declaration and configuring itself accordingly. This allows for policy configuration errors to be caught at deployment time instead of runtime.|
There are two parts to be marked by policies using requires attribute. Interaction Policy is allowed on component service and component reference. Implementation Policy is allowed on component implementation. Each policy belongs to one of these. Implementation Policy is NOT allowed to be marked on component service nor component reference, and Interaction Policy is NOT allowed to be marked on component implementation.
Transaction Interaction Policy is specified using the requires attribute of a component service or component reference definition.
Valid values for transaction interaction policy are:
- propagatesTransaction - indicates that a global transaction is required when a service is invoked. If no transaction is present, the SwitchYard runtime will generate an error.
- suspendsTransaction - if a transaction is present, the transaction is suspended before the service implementation is invoked and resumed after the invocation. This policy setting allows the transactional context of a gateway binding to be separated from the transactional context of the service implementation (e.g. a rollback in the service implementation will not impact the transaction used to receive a message from a JMS queue).
Transaction Implementation Policy is specified using the requires attribute of a component implementation definition.
Valid values for transaction implementation policy are:
- managedTransaction.Global - indicates that this service implementation runs under global transaction. If no transaction is present, the SwitchYard runtime will create a new JTA transaction before the execution. Created transaction will be committed by SwitchYard runtime at the end of service execution.
- managedTransaction.Local - indicates that this service implementation runs under local transaction containment. If transaction exists, SwitchYard runtime suspends it. And SwitchYard always create a new JTA transaction before the execution. Created transaction will be committed and suspended transcation will be resumed by SwitchYard runtime after the invocation. Note that since the local transaction containment doesn't propagate its transaction through the reference, all of the component reference must be marked as suspendsTransaction. If not, SwitchYard will automatically add suspendsTransaction.
- noManagedTransaction - indicates that this service implementation runs under no managed transaction. If transaction exists, SwitchYard runtime suspends it before the service implementation is invoked and resumed after the invocation.
Even if exchange state is fault, SwitchYard runtime doesn't automatically rollback the transaction by default. If you want the transaction to be marked as rollback-only on fault exchange, then you need to set "org.switchyard.rollbackOnFault" context property as true. Note that transaction is rolledback if unchecked exception is thrown regardless of this context property.
Currently, the following gateways are transaction aware. More gateways will be added in the future.
- Camel JMS Gateway (binding.jms)
- Camel JPA Gateway (binding.jpa)
- Camel SQL Gateway (binding.sql)
- JCA Gateway (binding.jca)
- SCA Gateway (binding.sca)
|BPM service and transaction|
BPM service (implementation.bpm) always need a JTA transaction if the persistence is enabled. It synchronizes with incoming transaction if exists, otherwise it begins a new JTA Transaction and commit/rollback by itself.
|Camel bindings and transaction|
If your application has multiple camel-jms bindings which are bound to the same JMS provider, you need to define distinct connection factory for each binding to get Transaction Policy working. otherwise, transaction can't be suspended as expected. Similarly, distinct xa-datasource is needed to get Transaction Policy working on camel-jpa and camel-sql. (cf. https://issues.jboss.org/browse/SWITCHYARD-1285)
Security Interaction Policy is specified using the requires attribute of a component service definition.
Valid values for security interaction policy are:
- clientAuthentication - indicates that the client has been authenticated when a service is invoked. If the associated authenticated user Principal is not available, the SwitchYard runtime will generate an error.
- confidentiality - indicates that the data in the request is not viewable by unintended parties. One example of this is when a request is made over SSL. Another example is if a SOAP message is encrypted according to WS-Security. If confidentiality cannot be verified, the SwitchYard runtime will generate an error.
Security Implementation Policy is specified using the requires attribute of a component implementation definition.
Valid values for security implementation policy are:
- authorization - indicates that the the client is authorized to invoke the service. Please refer to the rolesAllowed and runAs attributes on the security configuration element in the Security section of the documentation for details. If the associated authenticated Subject does not have an allowed role, the SwitchYard runtime will generate an error.
When the container does not automatically provide certain security policies, SwitchYard can be configured to process security credentials extracted from the binding-specific data, then provide certain security policies itself (like clientAuthentication). See the Security section of the documentation for details.
Support for security policy is limited to bean services (implementation.bean), SOAP endpoints via the SOAP gateway (binding.soap), and HTTP endpoints via the HTTP gateway (binding.http). Support for other implementation types and gateways will be added in the future.