The term “policy” can mean many things. When some people talk about policy, they are referring to governance rules that mandate steps and procedures that must be followed in order to develop, deploy, or modify an application. This is not what is meant by “policy” in SCA.
In SCA, a policy is a statement that controls or constrains some capability that is provided by the infrastructure.
Examples of infrastructure capabilities that can be managed using SCA’s policy framework include the following:
• Authentication
• Confidentiality (encryption)
• Integrity (signing)
• One-way message reliability
• Transaction propagation
These are not just arbitrary examples. They are the set of policies that were in the minds of the designers of SCA’s policy mechanism, so they should work fairly well. For other things that might be described as policies, the more they differ from the preceding examples, the less likely they are to be well-suited to SCA’s policy framework. Service level agreements (SLAs), such as promises about the average latency that will be provided by a service, are near the edge of this distinction. We do not know of any reason why they should not be well-suited to SCA’s policy framework, but there is also very little experience with the framework.
When we say that policies are capabilities provided by the infrastructure, we are differentiating them from the capabilities that are part of the code of components. Application code should not deal with the numerous transport and protocol issues that surround the sending and receiving of messages. Developers should be able to just concentrate on the application logic.
Nonetheless, it is sometimes necessary for someone to provide details about how certain infrastructure capabilities will be provided. For example, what encryption standard will be used to achieve confidentiality? In SCA, the person who makes those decisions and configures the associated details is the policy administrator.
Before going into more detail on features of the policy framework, it is useful to get an overview of the policy mechanism by looking at how encryption would be specified by the various roles involved in application development.
The developer specifies an @Confidentiality
annotation next to the @Reference
annotation that designates a reference. This turns into a reference declaration in the component type that includes the following:
<reference requires="sca:confidentiality" ...>
That @requires
attribute holds a list of intents. This means that the developer requires that some mechanism must be used to ensure confidentiality on calls through this reference.
It is the job of the policy administrator to make sure that the “confidentiality” intent lines up with a policySet
. The policy set definition contains policy assertions (usually in the form of WS-Policy), the intent that is guaranteed by that policy set, and the circumstances in which it applies. The circumstances are in the form of an XPath expression run on the binding where the policy will be used, although in many cases, the XPath expression can just be the name of the binding type (for example, @appliesTo="binding.ws"
).
Policy administrators install these policies by including them in definitions.xml files that are installed into the domain using the contribution mechanism, which will be described in Chapter 9, “The Domain.”
An intent specifies a capability without identifying how it will be provided. The definition of an intent is specified in a definition.xml file that may be installed into a domain using a contribution. However, runtimes usually have a number of intents preinstalled, such as the intents that are specified by the SCA standard itself.
Listing 6.1 provides the definition of SCA’s confidentiality intent.
The intent can be specified in implementation files, interface files, component types, and composites. In component types and composites, the intents are specified as a space-separated list in an @requires
attribute. The attribute can be put on any element. For binding and implementation elements, the attribute directly affects the element.
For any other element, the effect is indirect. The required intents are added to any binding or implementation element that is a descendent of the element that defines it (using the XML hierarchy). This enables you to specify confidentiality on every binding within a composite by specifying @requires="sca:confidentiality"
on the composite element itself. In some cases, compositewide intents might be overridden by intents on lower-level elements.
Transaction policy is an example of a situation where the component developer needs to be able to declare that it needs something from the infrastructure. Only the developer of a component knows if an atomicity guarantee is required for a component. If atomicity is required, the component must be developed in a way that guarantees any operation will either complete in its entirety, or the system will be put back into the same state it was in before the operation began.
One way to achieve this guarantee is for both client and service providers to create appropriate compensation logic, which undoes any completed steps if there is a failure before the entire logical transaction completes. Creating such compensation logic is a pain but is necessary if transactions can’t be used. This can happen if a component has references to services that can’t enlist in the same transaction as the component.
If transactions can be used, guaranteeing atomicity is much simpler. In order to include a service call in the transaction of the caller, SCA defines an intent called propagatesTransaction
. If this intent is present on a reference, the reference must be wired to a service that can enlist in the transaction. This frees the developer from creating compensation logic. However, it also constrains the deployer, because the reference can only be wired to services that can join the transaction. The propagatesTransaction
intent places this constraint.
In the example from the previous chapter, the credit component might mark its references to the scoring system and the audit system as needing to enlist in the transaction, so the scoring result is recorded in the audit log, no matter what. Figure 6.1 shows the references that require propagatesTransaction
in white.
policySets
policySet
s are defined by policy administrators, and they state the details of how a particular intent should be accomplished under various circumstances. policySet
definitions are found in definition.xml files, which can be installed in a domain via a contribution.
policySet
definitions hold collections of policy assertions that accomplish some intent (or set of intents) under curtain circumstances. The policy assertions are typically WS-Policy expressions, although other policy languages are allowed. The intents that the policySet
accomplishes are listed in the definition of the policy set in a @provides
attribute. The circumstances where the policySet
applies are represented as an XPath expression inside an @appliesTo
attribute.
For example, the propagatesTransaction
intent listed previously would be provided by the following policySet
(see Listing 6.2).
The contents of this policySet
is a WS-Policy assertion that was defined in the WS-AtomicTransaction specification. The @provides
attribute lists the sca:propagatesTransaction
intent as the only intent that is provided by the policySet
.
The @appliesTo
attribute is actually a relative XPath expression, although in this case, as in many cases, it is simply a QName.
@appliesTo
Is UsedThe processing rule for the @appliesTo
XPath expression is that it runs against the parent element of every binding or implementation element in the document. If the relative XPath expression returns the binding or implementation element that you are checking, this policySet
applies to this binding; if not, it doesn’t.
The result of this processing rule is that the most common thing that determines the applicability of a policySet
, the binding type, is specified with an XPath expression that is just the QName of the binding, such as "sca:binding.ws"
. That XPath expression run on the parent element of some binding.ws element will return all bindings with a QName of sca:binding.ws
. Because the binding being checked is in this set, the policySet
applies.
If you only wanted a policySet
to apply if the @uri
attribute on the binding starts with the “https” scheme, you would write the appliesTo
attribute as follows:
appliesTo="sca:binding.ws[starts-with(@uri, "https:")]"
You can also apply bindings only when they are used in specific contexts. For example, you could write a policySet
that is used on services or references that use the CreditService
WSDL interface, by using an appliesTo
of the following:
sca:binding.ws[../interface.wsdl/@interface="bb:CreditService"]
The conditional part traverses to the parent element (the “..
”), which will be either a service or a reference element. Either of these can specify their interface using interface.wsdl, so this finds the ones whose interface.wsdl has a @name
attribute with the QName of "bb:CreditService"
.
The SCA Policy Framework specification has a detailed algorithm that describes how to propagate intents down the XML hierarchy and how to find a matching policy set. The algorithm works on a composite, and the result of the algorithm should be that all intents are discovered to be satisfied in some way—either by finding an appropriate policy set or because of the built-in capabilities of bindings or implementations.
Some of the basic steps in the algorithm are the following:
1. Copy intents from each component type (that is, from the implementation) into the components that use those component types.
2. Copy in the intents from the interfaces used by any service or reference.
3. Propagate intents down the XML tree.
4. For each binding or implementation in the composite, find the smallest set of policy sets that provide all the intents listed for that binding or implementation and where the @appliesTo
matches.
If there are any bindings or implementations where no set of policySets
can be found that achieve that set of intents, there is an error. If more than one set can be found that achieve it, the deployer has to choose.
When policy sets are found for each binding, SCA has to make sure the resulting wires are valid from a policy perspective. SCA does not define how it accomplishes this for anything other than WS-Policy.
For WS-Policy, SCA uses the policy intersection algorithm that was defined in WS-Policy. The policy expressions on the bindings on each side of a wire have to line up (intersect) in order for the wire to be valid.
With our PropagatesTransaction
example, the WS-Policy assertion is <wsat:ATAssertion>
. In order for there to be a match, both sides of the wire need to have that assertion. If both sides don’t specify it, there is no match and the wire is invalid.
The fact that the WS-Policy matching algorithm would fail when the reference has the ATAssertion
and the service does not is appropriate in this scenario. In essence, the reference is saying: “I must be wired to a service that knows how to undo its work if I ever roll back, because I don’t have any compensation handling logic.” If the service doesn’t declare that it can join the transaction, as far as SCA can tell, it will not be able to, and the requirement made by the reference is not met.
The preceding scenario used a trivial WS-Policy expression. It had a single policy assertion, <wsat:ATAssertion>
, which had to exist on both sides of the wire. In general, WS-Policy matching is a bit more complicated than this, because each side of the wire can include arbitrarily complex expressions that involve optional policy assertions or alternative assertions. WS-Policy does not define any specific policies; it just describes an expression language for combining them. The concepts defined by WS-Policy are the following:
• Policy assertion—Policy assertions are the atoms from which larger policy expressions can be built. A policy assertion is simply an XML element. It can come from any namespace. Two policy assertions definitely match if they have the same element QName, the same attribute values, and the same subelements (if any). If they differ, the policy assertions may or may not match—it depends on the definition of the policy assertion (what a pain!).
• ExactlyOne E1, E2, ...—This says that E1, E2, and so on are policy choices. Exactly one of those policy expressions must be used when using the service.
• All E1, E2, ...—This says that expressions E1, E2, and so on are policy expressions that must be enforced together.
• Optional policy assertions—A policy assertion may be marked with an attribute of wsp:optional="true"
. This means that the policy is available if the other side of the wire asks for it, but it isn’t required by this side. It is defined as a macro expansion of an ExactlyOne with two subexpressions—one with the assertion, and one without it.
• Ignorable policy assertions—A policy assertion may be marked with an attribute of wsp:ignorable="true"
. This is used to declare characteristics of a service that don’t require cooperation from both sides—such as audit logging. One side of the wire is declaring that it is going to do something (for example, log messages). This way, if the other side of the wire requires that it should only be wired to services that do such logging, the assertion is there to cover it. If the other side doesn’t care, the wire will work anyway (and the logging will happen anyway).
Looking at the preceding concepts, you can see that they are basically the XOR and AND operators from predicate logic. It is notable that they do not have the inclusive OR operator or the NOT operator. The lack of a NOT operator means that it is not possible for a reference, for example, to say that it must not be wired to a service that does audit logging.
The lack of an inclusive OR means that if a service can do A, B, or A and B, instead of just being able to say:
</Or><A/><B/></Or>
it must say:
So, inclusive OR is possible; it is just ugly.
Because WS-Policy doesn’t define any policy assertions, it must leave those to other specifications. Some of the specifications that define standard policy assertions include WS-AT, WS-SecurityPolicy, or WS-ReliabilityPolicy.
There is one final important concept that WS-Policy defines, as follows:
• Policy intersection—This is used for determining if two policies are “compatible.” The two policies are set side-by-side, and any place one side has an exactlyOne
, the other side has to have a policy expression that matches one of the alternatives (possibly also within an exactlyOne
). The intersection continues in a predictable manner given the concepts defined previously. One thing that is noteworthy about WS-Policy intersection is that it is symmetric. The service provider and the service client both specify policy expressions, and the two sides are treated the same. This may seem odd at first, because service providers seem like the more natural place to declare requirements on any client of that service. (After all, WSDL is only defined for the provider side, not for clients.) But, in fact, clients may sometimes have requirements of their own, which need to be communicated to whatever human or system is going to be finding a matching service.
Returning to our example, consider the one wire between the Credit
and the Scoring
components (see Figure 6.2).
Each of these intents will resolve to the same policySet
—namely, the policySet
mentioned previously:
The policy infrastructure requires the intersection of the policies on each end of the wire in order to determine the policy actually used. In this case, this becomes the intersection of a policySet
with itself, so the intersection is the same as the original policySet
.
Because the <wsat:ATAssertion/>
policy assertion is present on the wire, the transaction will be propagated.
SCA also defines a few intents related to the reliability of one-way messaging.
Let’s return to the application presented in Chapter 5, “Composition,” but this time after it ended up looking like what is shown in Figure 6.3.
The outermost composite in this picture is shown in Listing 6.3.
We haven’t previously looked at the interface for the AuditComponent
, so let’s do that now. AuditComponent
will have a single @OneWay
operation called auditEntry
, which takes as a parameter a string representation of the auditable step that needs to be recorded (see Listing 6.4).
The operation is a one-way operation, because it does not want to slow down the normal flow of the business logic. However, it is also important that the audit entries not get lost! This is where policy can help. We should add the following requirements to this wire:
• exactlyOnce
—So that we don’t lose any audit entries, and none get entered multiple times
• authentication
—So that no one forges an audit entry
• integrity
—So that the entries are signed, preventing third-party modification of the audit entry
To add these requirements to LoanApplicationComposite
, all that is necessary is to add an entry for each of these requirements into a @requires
attribute of the reference (see Listing 6.5).
There are times when a developer might want to specify more about how a generic capability is going to be provided than is possible with simple intents. Qualified intents are intents that provide this additional detail beyond some existing simple intent.
Consider the confidentiality intent that was introduced at the beginning of this chapter. Confidentiality is typically accomplished through encryption, although different mechanisms exist. Some handle encryption on a point-to-point basis. This is typically called transport-level encryption. Other techniques exist to encrypt a message in such a way that intermediaries can process and route the message without decrypting the body of the message. This is called message-level encryption.
If a developer specifies that she requires sca:Confidentiality
on a reference, this does not constrain the kind of encryption technique that is used. However, some developers may know enough about the data and the way it is supposed to be protected to know that message-level encryption is required. In this case, it should be possible to require message-level encryption, but still to do it at the level of intents, rather than having to dive down into the details of a specific binding.
In SCA, an intent may be qualified by extending it with a “.
” and the name of some valid qualifier for that intent. In the case of confidentiality, there are two qualifiers, which are written as sca:Confidentiality.Message
and sca:Confidentiality.Transport
.
Qualified intents are not independent intents from intents that they qualify. The most important relationship between them is the fact that anything that satisfies a qualified intent also implicitly satisfies the intent that it qualifies. This is especially useful between the various roles involved in application development. If a developer requires a specific intent, an assembler or deployer may further refine that requirement by requiring a qualified version of the intent.
Even within a single role, it is sometimes valuable to specify a more general intent that applies broadly, perhaps to everything within a composite, and then to refine that general intent down to a specific intent for some specific service. For example, the confidentiality intent might be specified on the composite, but some of its services might specify Confidentiality.Message
.
There are times when a collection of intents are so frequently used together that it makes sense to have a single intent that expands into other intents. A profile intent is such an intent. The definition of a profile intent includes a @requires
attribute that lists the intents that it should expand into.
Among the set of standard SCA intents, the reliability intent of sca:ExactlyOnce
is a profile intent that expands to sca:AtLeastOnce
and sca:AtMostOnce
. As is always the case with an @requires
attribute, the semantics of the list is AND—all the intents must be satisfied.
Listing 6.6 presents the definition of the sca:ExactlyOnce
profile intent.
A variety of the standardized intents have been referenced in the previous section. The following is an exhaustive list of the intents that have been standardized as of SCA 1.0. All these intents are in the SCA namespace.
The security intents include the following:
• Authentication
—The identity of the requestor of the service must be verified.
• Confidentiality
—Some mechanism (such as encryption) must be used to prevent a message from being read by anyone other than the intended recipient of the message.
• Integrity
—A message must be protected from being surreptitiously modified after it has been created (such as by attaching an electronic signature).
Each of the three preceding intents have the following two qualifiers:
• Transport
—The guarantee need only be guaranteed at the transport level (that is, for a single hop).
• Message
—The guarantee should be at the message level. It should provide an end-to-end guarantee.
The delivery intents include the following:
• AtLeastOnce
—At least one copy of the message must be delivered (duplicates allowed).
• AtMostOnce
—At most, one copy of the message must be delivered (no duplicates; dropped messages allowed).
• ExactlyOnce
—The message must be delivered once and only once.
• Ordered
—Messages from the same client must be delivered in the same order that they were sent.
Transaction intents include the following:
• PropagatesTransaction
—The intent requires that the other side of the wire must be able to be in the same transaction. If the intent is on a reference, it means that the service provider must be able to join the transaction. If it is on a service, it means that the client must be able to provide a transaction to join. This must be used with ManagedTransaction.global
on the implementation.
• SuspendTransaction
—This intent goes on service and references and prevents any transaction that might be active from being shared across that wire.
• ManagedTransaction
—This intent goes on implementations and means that the components must be run within some kind of transactional environment, although it may not be global. Usually this means that it has to be able to use a database to do the work of a method as one atomic unit (without having to specify explicitly transaction boundaries), but doesn’t need to share its transaction with its clients or its downstream services.
• ManagedTransaction.Global
—This is a qualified intent that extends ManagedTransaction
to say that the transaction must be one that can enlist upstream or downstream components.
• ManagedTransaction.Local
—This qualifier clarifies that a local transaction, rather than a global transaction, should be used. This provides better performance, but introduces the possibility that a system crash could cause the changes to one resource to be lost even while changes made from the same transaction to a different resource are committed.
• NoManagedTransaction
—No managed transaction should be used.
Miscellaneous intents include the following:
• SOAP
—The SOAP messaging model should be used. Note that this does not constrain the transport that might be used to send the SOAP message. If it is unqualified, any version of the SOAP standard may be used.
• SOAP.1_1
—The SOAP v.1.1 standard message model must be used.
• SOAP.1_2
—The SOAP v.1.2 standard message model must be used.
• JMS
—This application uses the JMS API, so the binding must support this API.
• NoListener
—The binding must be able to handle any incoming traffic through the back channel of an outbound request. There is no listener for inbound traffic. For asynchronous responses, the binding may need to use polling.
This chapter has covered using SCA policy to declaratively configure such things as transactions, security, and reliability. One of the key goals of SCA policy is to abstract the complexity associated with specifying security, reliability, and other qualities of service from application code. SCA achieves this policy abstraction by providing policy intents that are used by developers to signal the need for an abstract quality of service, and then are turned into concrete policies by policy administrators.