org.fabric3.policy.DefaultPolicyResolver Maven / Gradle / Ivy
/*
* Fabric3
* Copyright (c) 2009-2013 Metaform Systems
*
* Fabric3 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version, with the
* following exception:
*
* Linking this software statically or dynamically with other
* modules is making a combined work based on this software.
* Thus, the terms and conditions of the GNU General Public
* License cover the whole combination.
*
* As a special exception, the copyright holders of this software
* give you permission to link this software with independent
* modules to produce an executable, regardless of the license
* terms of these independent modules, and to copy and distribute
* the resulting executable under terms of your choice, provided
* that you also meet, for each linked independent module, the
* terms and conditions of the license of that module. An
* independent module is a module which is not derived from or
* based on this software. If you modify this software, you may
* extend this exception to your version of the software, but
* you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version.
*
* Fabric3 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the
* GNU General Public License along with Fabric3.
* If not, see .
*/
package org.fabric3.policy;
import javax.xml.namespace.QName;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.fabric3.host.Namespaces;
import org.fabric3.model.type.component.ComponentDefinition;
import org.fabric3.model.type.component.Implementation;
import org.fabric3.model.type.contract.Operation;
import org.fabric3.model.type.contract.ServiceContract;
import org.fabric3.model.type.definitions.Intent;
import org.fabric3.model.type.definitions.PolicyPhase;
import org.fabric3.model.type.definitions.PolicySet;
import org.fabric3.policy.resolver.ImplementationPolicyResolver;
import org.fabric3.policy.resolver.IntentPair;
import org.fabric3.policy.resolver.InteractionPolicyResolver;
import org.fabric3.spi.contract.OperationNotFoundException;
import org.fabric3.spi.contract.OperationResolver;
import org.fabric3.spi.generator.EffectivePolicy;
import org.fabric3.spi.generator.PolicyMetadata;
import org.fabric3.spi.generator.policy.PolicyResolutionException;
import org.fabric3.spi.generator.policy.PolicyResolver;
import org.fabric3.spi.generator.policy.PolicyResult;
import org.fabric3.spi.model.instance.Bindable;
import org.fabric3.spi.model.instance.LogicalBinding;
import org.fabric3.spi.model.instance.LogicalComponent;
import org.fabric3.spi.model.instance.LogicalConsumer;
import org.fabric3.spi.model.instance.LogicalOperation;
import org.fabric3.spi.model.instance.LogicalReference;
import org.fabric3.spi.model.instance.LogicalService;
import org.fabric3.spi.model.instance.LogicalWire;
import org.fabric3.spi.model.type.binding.LocalBindingDefinition;
import org.fabric3.spi.model.type.binding.RemoteBindingDefinition;
import org.fabric3.util.closure.Closure;
import org.fabric3.util.closure.CollectionUtils;
import org.oasisopen.sca.annotation.Reference;
/**
*
*/
public class DefaultPolicyResolver implements PolicyResolver {
private static final QName IMPLEMENTATION_SYSTEM = new QName(Namespaces.F3, "implementation.system");
private static final QName IMPLEMENTATION_SINGLETON = new QName(Namespaces.F3, "singleton");
private static final PolicyResult EMPTY_RESULT = new NullPolicyResult();
private static final Operation DEFINITION = new Operation("_fabric3Generated", null, null, null);
/**
* Closure for filtering intercepted policies.
*/
private static final Closure INTERCEPTION = new Closure() {
public Boolean execute(PolicySet policySet) {
return policySet.getPhase() == PolicyPhase.INTERCEPTION;
}
};
/**
* Closure for filtering provided policies by bindings or implementations.
*/
private static final Closure PROVIDED = new Closure() {
public Boolean execute(PolicySet policySet) {
return policySet.getPhase() == PolicyPhase.PROVIDED;
}
};
private InteractionPolicyResolver interactionResolver;
private ImplementationPolicyResolver implementationResolver;
private OperationResolver operationResolver;
public DefaultPolicyResolver(@Reference InteractionPolicyResolver interactionResolver,
@Reference ImplementationPolicyResolver implementationResolver,
@Reference OperationResolver operationResolver) {
this.interactionResolver = interactionResolver;
this.implementationResolver = implementationResolver;
this.operationResolver = operationResolver;
}
public PolicyResult resolvePolicies(LogicalBinding> binding) throws PolicyResolutionException {
Bindable parent = binding.getParent();
LogicalBinding remoteBinding = new LogicalBinding(RemoteBindingDefinition.INSTANCE, parent);
Bindable bindable = binding.getParent();
if (bindable instanceof LogicalReference) {
return resolvePolicies(bindable.getOperations(), remoteBinding, binding, bindable.getParent(), null);
} else if (bindable instanceof LogicalService) {
return resolvePolicies(bindable.getOperations(), binding, remoteBinding, null, bindable.getParent());
} else {
throw new UnsupportedOperationException();
}
}
public PolicyResult resolveCallbackPolicies(LogicalBinding> binding) throws PolicyResolutionException {
LogicalBinding remoteBinding = new LogicalBinding(RemoteBindingDefinition.INSTANCE,
binding.getParent());
Bindable bindable = binding.getParent();
if (bindable instanceof LogicalReference) {
return resolvePolicies(bindable.getCallbackOperations(), remoteBinding, binding, bindable.getParent(), null);
} else if (bindable instanceof LogicalService) {
return resolvePolicies(bindable.getCallbackOperations(), remoteBinding, binding, bindable.getParent(), null);
} else {
throw new IllegalArgumentException("Only services and references can have callback operations");
}
}
public PolicyResult resolveLocalPolicies(LogicalWire wire) throws PolicyResolutionException {
LogicalReference reference = wire.getSource();
// use the leaf service to optimize data paths - e.g. a promoted service may use a different service contract and databinding than the leaf
LogicalService service = wire.getTarget().getLeafService();
LogicalComponent source = reference.getParent();
LogicalComponent target = service.getLeafComponent();
LogicalBinding sourceBinding = new LogicalBinding(LocalBindingDefinition.INSTANCE, reference);
LogicalBinding targetBinding = new LogicalBinding(LocalBindingDefinition.INSTANCE, service);
return resolvePolicies(reference.getOperations(), sourceBinding, targetBinding, source, target);
}
public PolicyResult resolveLocalCallbackPolicies(LogicalWire wire) throws PolicyResolutionException {
LogicalReference reference = wire.getSource();
LogicalService service = wire.getTarget();
LogicalComponent> targetComponent = reference.getParent();
ServiceContract referenceCallbackContract = reference.getServiceContract().getCallbackContract();
LogicalService callbackService = targetComponent.getService(referenceCallbackContract.getInterfaceName());
LogicalBinding sourceBinding = new LogicalBinding(LocalBindingDefinition.INSTANCE, callbackService);
LogicalBinding targetBinding = new LogicalBinding(LocalBindingDefinition.INSTANCE, reference);
LogicalComponent sourceComponent = service.getLeafComponent();
return resolvePolicies(service.getCallbackOperations(), sourceBinding, targetBinding, sourceComponent, targetComponent);
}
public PolicyResult resolveRemotePolicies(LogicalWire wire) throws PolicyResolutionException {
LogicalReference reference = wire.getSource();
LogicalService service = wire.getTarget();
LogicalComponent source = reference.getParent();
LogicalComponent target = service.getLeafComponent();
LogicalBinding> serviceBinding = wire.getTargetBinding();
List sourceOperations = reference.getOperations();
return resolvePolicies(sourceOperations, serviceBinding, serviceBinding, source, target);
}
public PolicyResult resolveRemoteCallbackPolicies(LogicalWire wire) throws PolicyResolutionException {
LogicalReference reference = wire.getSource();
LogicalComponent target = reference.getParent();
ServiceContract referenceContract = reference.getServiceContract();
ServiceContract referenceCallbackContract = referenceContract.getCallbackContract();
LogicalBinding> referenceBinding = reference.getCallbackBindings().get(0);
LogicalService callbackService = target.getService(referenceCallbackContract.getInterfaceName());
List operations = reference.getCallbackOperations();
LogicalBinding sourceBinding = new LogicalBinding(LocalBindingDefinition.INSTANCE, callbackService);
return resolvePolicies(operations, sourceBinding, referenceBinding, null, target);
}
public PolicyResult resolvePolicies(LogicalConsumer consumer) throws PolicyResolutionException {
LogicalComponent> component = consumer.getParent();
if (noPolicy(component)) {
return EMPTY_RESULT;
}
// synthesize an operation and binding
PolicyResultImpl policyResult = new PolicyResultImpl();
LogicalOperation operation = new LogicalOperation(DEFINITION, consumer);
IntentPair targetOperationIntentPair = interactionResolver.resolveIntents(operation, LocalBindingDefinition.INSTANCE.getType());
policyResult.addTargetProvidedIntents(operation, targetOperationIntentPair.getProvidedIntents());
IntentPair sourceImplementationIntentPair = implementationResolver.resolveIntents(component, operation);
policyResult.addSourceProvidedIntents(operation, sourceImplementationIntentPair.getProvidedIntents());
Set policies = interactionResolver.resolvePolicySets(operation, consumer, LocalBindingDefinition.INSTANCE.getType());
policyResult.addTargetPolicySets(operation, CollectionUtils.filter(policies, PROVIDED));
policyResult.addInterceptedPolicySets(operation, CollectionUtils.filter(policies, INTERCEPTION));
// resolve policies using the target (as opposed to source) operation so target implementation policies are included
policies = implementationResolver.resolvePolicySets(component, operation);
// add policy metadata to the result
PolicyMetadata metadata = policyResult.getMetadata(operation);
metadata.addAll(operation.getDefinition().getMetadata());
// add metadata from implementation
metadata.addAll(operation.getParent().getParent().getDefinition().getImplementation().getMetadata());
// important: use reference side operation as the key
policyResult.addTargetPolicySets(operation, CollectionUtils.filter(policies, PROVIDED));
policyResult.addInterceptedPolicySets(operation, CollectionUtils.filter(policies, INTERCEPTION));
overrideDirectIfExternalAttachedPolicies(policyResult);
return policyResult;
}
private PolicyResult resolvePolicies(List operations,
LogicalBinding> sourceBinding,
LogicalBinding> targetBinding,
LogicalComponent> source,
LogicalComponent> target) throws PolicyResolutionException {
if ((noPolicy(source) && noPolicy(target))) {
return EMPTY_RESULT;
}
PolicyResultImpl policyResult = new PolicyResultImpl();
resolveEndpointPolicies(policyResult, sourceBinding, targetBinding);
for (LogicalOperation operation : operations) {
resolveOperationPolicies(operation, policyResult, sourceBinding, targetBinding, target);
}
overrideDirectIfExternalAttachedPolicies(policyResult);
return policyResult;
}
private void overrideDirectIfExternalAttachedPolicies(PolicyResult policyResult) throws PolicyResolutionException {
Set sets = policyResult.getInterceptedEndpointPolicySets();
boolean overrode = overrideDirectIfExternalAttachedPolicies(sets);
for (List policies : policyResult.getInterceptedPolicySets().values()) {
if (overrideDirectIfExternalAttachedPolicies(policies)) {
overrode = true;
}
}
sets = policyResult.getSourcePolicy().getEndpointPolicySets();
if (overrideDirectIfExternalAttachedPolicies(sets)) {
overrode = true;
}
for (List policies : policyResult.getSourcePolicy().getOperationPolicySets().values()) {
if (overrideDirectIfExternalAttachedPolicies(policies)) {
overrode = true;
}
}
sets = policyResult.getTargetPolicy().getEndpointPolicySets();
if (overrideDirectIfExternalAttachedPolicies(sets)) {
overrode = true;
}
for (List policies : policyResult.getTargetPolicy().getOperationPolicySets().values()) {
if (overrideDirectIfExternalAttachedPolicies(policies)) {
overrode = true;
}
}
// validate that intents are still satisfied if an external attachment policy set overrode direct attached policy sets
if (overrode) {
validatePolicy(policyResult.getSourcePolicy());
validatePolicy(policyResult.getTargetPolicy());
}
}
private void validatePolicy(EffectivePolicy policy) throws PolicyResolutionException {
Collection aggregatedIntents = policy.getAggregatedEndpointIntents();
Collection provideIntents = policy.getProvidedEndpointIntents();
Collection sets = policy.getEndpointPolicySets();
validatePolicySets(aggregatedIntents, provideIntents, sets);
aggregatedIntents = policy.getOperationIntents();
for (List operationSets : policy.getOperationPolicySets().values()) {
validatePolicySets(aggregatedIntents, provideIntents, operationSets);
}
}
private void validatePolicySets(Collection aggregatedIntents, Collection provideIntents, Collection sets)
throws PolicyResolutionException {
for (Intent intent : aggregatedIntents) {
if (provideIntents.contains(intent)) {
// provided natively, ignore
continue;
}
boolean provided = false;
for (PolicySet set : sets) {
if (set.doesProvide(intent.getName())) {
provided = true;
break;
}
}
if (!provided) {
throw new PolicyResolutionException("Intent not satisfied by external attached policies:" + intent.getName());
}
}
}
private boolean overrideDirectIfExternalAttachedPolicies(Collection policies) {
boolean externalAttachment = false;
for (PolicySet policySet : policies) {
if (policySet.getAttachTo() != null) {
externalAttachment = true;
break;
}
}
if (externalAttachment) {
for (Iterator iterator = policies.iterator(); iterator.hasNext(); ) {
PolicySet policySet = iterator.next();
if (policySet.getAttachTo() == null) {
iterator.remove();
}
}
}
return externalAttachment;
}
/**
* Resolves configured source and target intents and policies for an endpoint. Resolution will be performed against the bindings and ancestors.
*
* @param policyResult the policy result to populate
* @param sourceBinding the source binding
* @param targetBinding the target binding
* @throws PolicyResolutionException if there is a resolution error
*/
private void resolveEndpointPolicies(PolicyResultImpl policyResult, LogicalBinding> sourceBinding, LogicalBinding> targetBinding)
throws PolicyResolutionException {
IntentPair sourceEndpointIntentPair = interactionResolver.resolveIntents(sourceBinding);
policyResult.addSourceProvidedEndpointIntents(sourceEndpointIntentPair.getProvidedIntents());
policyResult.addSourceAggregatedEndpointIntents(sourceEndpointIntentPair.getAggregatedIntents());
IntentPair targetEndpointIntentPair = interactionResolver.resolveIntents(targetBinding);
policyResult.addTargetProvidedEndpointIntents(targetEndpointIntentPair.getProvidedIntents());
policyResult.addTargetAggregatedEndpointIntents(targetEndpointIntentPair.getAggregatedIntents());
Set endpointPolicies = interactionResolver.resolvePolicySets(sourceBinding);
policyResult.addSourceEndpointPolicySets(CollectionUtils.filter(endpointPolicies, PROVIDED));
policyResult.addInterceptedEndpointPolicySets(CollectionUtils.filter(endpointPolicies, INTERCEPTION));
endpointPolicies = interactionResolver.resolvePolicySets(targetBinding);
policyResult.addTargetEndpointPolicySets(CollectionUtils.filter(endpointPolicies, PROVIDED));
policyResult.addInterceptedEndpointPolicySets(CollectionUtils.filter(endpointPolicies, INTERCEPTION));
}
/**
* Resolves configured source and target intents and policies for an operation.
*
* @param operation the operation
* @param policyResult the policy result to populate
* @param sourceBinding the source binding
* @param targetBinding the target binding
* @param target the target component, or null if the operation invokes a remote service
* @throws PolicyResolutionException if there is a resolution error
*/
private void resolveOperationPolicies(LogicalOperation operation,
PolicyResultImpl policyResult,
LogicalBinding> sourceBinding,
LogicalBinding> targetBinding,
LogicalComponent> target) throws PolicyResolutionException {
QName sourceType = sourceBinding.getDefinition().getType();
IntentPair sourcePair = interactionResolver.resolveIntents(operation, sourceType);
policyResult.addSourceProvidedIntents(operation, sourcePair.getProvidedIntents());
QName targetType = targetBinding.getDefinition().getType();
IntentPair targetPair = interactionResolver.resolveIntents(operation, targetType);
policyResult.addTargetProvidedIntents(operation, targetPair.getProvidedIntents());
if (target != null) {
IntentPair sourceImplementationPair = implementationResolver.resolveIntents(target, operation);
policyResult.addSourceProvidedIntents(operation, sourceImplementationPair.getProvidedIntents());
}
Set policies = interactionResolver.resolvePolicySets(operation, sourceBinding, sourceType);
policyResult.addSourcePolicySets(operation, CollectionUtils.filter(policies, PROVIDED));
policyResult.addInterceptedPolicySets(operation, CollectionUtils.filter(policies, INTERCEPTION));
policies = interactionResolver.resolvePolicySets(operation, targetBinding, targetType);
policyResult.addTargetPolicySets(operation, CollectionUtils.filter(policies, PROVIDED));
policyResult.addInterceptedPolicySets(operation, CollectionUtils.filter(policies, INTERCEPTION));
if (target != null) {
Bindable parent = targetBinding.getParent();
// resolve policies using the target (as opposed to source) operation so target implementation policies are included
LogicalOperation targetOperation = matchOperation(operation, parent);
policies = implementationResolver.resolvePolicySets(target, targetOperation);
// add policy metadata to the result
PolicyMetadata metadata = policyResult.getMetadata(operation);
metadata.addAll(targetOperation.getDefinition().getMetadata());
// add metadata from implementation
ComponentDefinition extends Implementation>> parentDefinition = targetOperation.getParent().getParent().getDefinition();
Implementation> parentImplementation = parentDefinition.getImplementation();
metadata.addAll(parentImplementation.getMetadata());
// add metadata from component type
metadata.addAll(parentImplementation.getComponentType().getMetadata());
// important: use reference side operation as the key
policyResult.addTargetPolicySets(operation, CollectionUtils.filter(policies, PROVIDED));
policyResult.addInterceptedPolicySets(operation, CollectionUtils.filter(policies, INTERCEPTION));
}
}
/**
* Matches operation definitions on the source and target sides of a wire so that policy sets and intents can be determined. Note that if the source
* operation belongs to a service, the wire is a callback wire.
*
* @param operation the source operation to match against.
* @param bindable the target bindable.
* @return the matching operation
* @throws PolicyResolutionException if there is a matching error
*/
private LogicalOperation matchOperation(LogicalOperation operation, Bindable bindable) throws PolicyResolutionException {
String name = operation.getDefinition().getName();
List operations;
if (bindable instanceof LogicalReference) {
// target is a reference so this is a callback
operations = bindable.getCallbackOperations();
} else {
operations = bindable.getOperations();
}
try {
LogicalOperation matched = operationResolver.resolve(operation, operations);
if (matched == null) {
throw new AssertionError("No matching operation for " + name);
}
return matched;
} catch (OperationNotFoundException e) {
throw new PolicyResolutionException(e);
}
}
private boolean noPolicy(LogicalComponent> component) {
return component != null && (component.getDefinition().getImplementation().isType(IMPLEMENTATION_SYSTEM)
|| component.getDefinition().getImplementation().isType(IMPLEMENTATION_SINGLETON));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy