All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fabric3.policy.resolver.InteractionPolicyResolverImpl Maven / Gradle / Ivy

The newest version!
/*
 * Fabric3
 * Copyright (c) 2009-2015 Metaform Systems
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * Portions originally based on Apache Tuscany 2007
 * licensed under the Apache 2.0 license.
 */
package org.fabric3.policy.resolver;

import javax.xml.namespace.QName;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.fabric3.api.model.type.definitions.BindingType;
import org.fabric3.api.model.type.definitions.Intent;
import org.fabric3.api.model.type.definitions.PolicySet;
import org.fabric3.policy.infoset.PolicyEvaluator;
import org.fabric3.spi.domain.generator.policy.PolicyRegistry;
import org.fabric3.spi.domain.generator.policy.PolicyResolutionException;
import org.fabric3.spi.domain.LogicalComponentManager;
import org.fabric3.spi.model.instance.Bindable;
import org.fabric3.spi.model.instance.LogicalBinding;
import org.fabric3.spi.model.instance.LogicalOperation;
import org.fabric3.spi.model.instance.LogicalReference;
import org.fabric3.spi.model.instance.LogicalScaArtifact;
import org.oasisopen.sca.Constants;
import org.oasisopen.sca.annotation.Reference;

/**
 *
 */
public class InteractionPolicyResolverImpl extends AbstractPolicyResolver implements InteractionPolicyResolver {
    private static final QName TRANSACTED_ONEWAY = new QName(Constants.SCA_NS, "transactedOneWay");
    private static final QName IMMEDIATE_ONEWAY = new QName(Constants.SCA_NS, "immediateOneWay");
    private static final QName LOCAL_MANAGED_TRANSACTION = new QName(Constants.SCA_NS, "managedTransaction.local");
    private static final QName NO_MANAGED_TRANSACTION = new QName(Constants.SCA_NS, "noManagedTransaction");
    private static final QName PROPAGATES_TRANSACTION = new QName(Constants.SCA_NS, "propagatesTransaction");
    private static final QName ONEWAY = new QName(Constants.SCA_NS, "oneWay");
    private static final QName ASYNC_INVOCATION = new QName(Constants.SCA_NS, "asyncInvocation");
    private static final QName NO_LISTENER = new QName(Constants.SCA_NS, "noListener");

    public InteractionPolicyResolverImpl(@Reference PolicyRegistry policyRegistry,
                                         @Reference LogicalComponentManager lcm,
                                         @Reference PolicyEvaluator policyEvaluator) {
        super(policyRegistry, lcm, policyEvaluator);
    }

    public IntentPair resolveIntents(LogicalOperation operation, QName bindingType) throws PolicyResolutionException {
        Set requiredIntents = aggregateOperationIntents(operation);
        Set providedIntents = filterProvidedIntents(bindingType, requiredIntents);
        return new IntentPair(requiredIntents, providedIntents);
    }

    public IntentPair resolveIntents(LogicalBinding binding) throws PolicyResolutionException {
        Set requiredIntents = aggregateBindingIntents(binding);

        QName type = binding.getDefinition().getType();
        Set providedIntents = filterProvidedIntents(type, requiredIntents);
        return new IntentPair(requiredIntents, providedIntents);
    }

    public Set resolvePolicySets(LogicalBinding binding) throws PolicyResolutionException {
        QName type = binding.getDefinition().getType();
        BindingType bindingType = policyRegistry.getDefinition(type, BindingType.class);

        Set alwaysProvidedIntents = new LinkedHashSet<>();
        Set mayProvidedIntents = new LinkedHashSet<>();

        if (bindingType != null) {
            // tolerate a binding type not being registered
            alwaysProvidedIntents = bindingType.getAlwaysProvide();
            mayProvidedIntents = bindingType.getMayProvide();
        }

        // resolve policies against the binding
        Set requiredIntents = aggregateBindingIntents(binding);
        Set requiredIntentsCopy = new HashSet<>(requiredIntents);
        // Remove intents that are provided
        for (Intent intent : requiredIntentsCopy) {
            QName intentName = intent.getName();
            if (alwaysProvidedIntents.contains(intentName) || mayProvidedIntents.contains(intentName)) {
                requiredIntents.remove(intent);
            }
        }
        Set policies = resolvePolicies(requiredIntents, binding);
        if (!requiredIntents.isEmpty()) {
            throw new IntentResolutionException("Unable to resolve all intents", requiredIntents);
        }

        Set policySets = aggregateBindingPolicySets(binding);
        for (QName name : policySets) {
            PolicySet policySet = policyRegistry.getDefinition(name, PolicySet.class);
            policies.add(policySet);
        }

        return policies;
    }

    public Set resolvePolicySets(LogicalOperation operation, LogicalScaArtifact artifact, QName type) throws PolicyResolutionException {
        BindingType bindingType = policyRegistry.getDefinition(type, BindingType.class);

        Set alwaysProvidedIntents = new LinkedHashSet<>();
        Set mayProvidedIntents = new LinkedHashSet<>();

        // FIXME This should not happen, all binding types should be registered
        if (bindingType != null) {
            alwaysProvidedIntents = bindingType.getAlwaysProvide();
            mayProvidedIntents = bindingType.getMayProvide();
        }

        Set requiredIntents = aggregateOperationIntents(operation);
        Set requiredIntentsCopy = new HashSet<>(requiredIntents);

        // Remove intents that are provided
        for (Intent intent : requiredIntentsCopy) {
            QName intentName = intent.getName();
            if (alwaysProvidedIntents.contains(intentName) || mayProvidedIntents.contains(intentName)) {
                requiredIntents.remove(intent);
            }
        }
        Set policySets = getOperationPolicySets(operation);
        if (requiredIntents.isEmpty() && policySets.isEmpty()) {
            // short-circuit intent resolution
            return Collections.emptySet();
        }

        // resolve policies against the binding
        Set policies = resolvePolicies(requiredIntents, artifact);
        if (!requiredIntents.isEmpty()) {
            throw new IntentResolutionException("Unable to resolve all intents", requiredIntents);
        }

        for (QName name : policySets) {
            PolicySet policySet = policyRegistry.getDefinition(name, PolicySet.class);
            policies.add(policySet);
        }

        return policies;

    }

    private Set aggregateOperationIntents(LogicalOperation operation) throws PolicyResolutionException {
        Set intentNames = new LinkedHashSet<>();
        intentNames.addAll(operation.getIntents());
        return expandAndFilterIntents(intentNames, operation);
    }

    private Set aggregateBindingIntents(LogicalBinding binding) throws PolicyResolutionException {
        // Aggregate all the intents from the ancestors
        Set intentNames = aggregateIntents(binding);
        return expandAndFilterIntents(intentNames, binding);
    }

    private Set expandAndFilterIntents(Set intentNames, LogicalScaArtifact artifact) throws PolicyResolutionException {
        // Expand all the profile intents
        Set requiredIntents = resolveIntents(intentNames);

        validateIntents(requiredIntents, artifact);
        // Remove intents not applicable to the artifact
        filterInvalidIntents(Intent.BINDING, requiredIntents);
        filterMutuallyExclusiveIntents(requiredIntents);
        return requiredIntents;
    }

    /**
     * Validates intent combinations per the SCA policy spec where the intents do not specify this in their excludes configuration. This specifically deals with
     * implementation and messaging transaction policies and results in the hardcoded hack below.
     *
     * @param intents  the intents to validate.
     * @param artifact the artifact to which the intents apply
     */
    private void validateIntents(Set intents, LogicalScaArtifact artifact) throws PolicyResolutionException {
        if (intents.isEmpty()) {
            return;
        }
        boolean isTransactedOneWay = false;
        boolean isImmediateOneWay = false;
        boolean isNoManagedTransaction = false;
        boolean isLocalTransaction = false;
        boolean propagatesTransaction = false;
        boolean asyncInvocation = false;

        for (Intent intent : intents) {
            if (!isTransactedOneWay) {
                if (isTransactedOneWay = TRANSACTED_ONEWAY.equals(intent.getName())) {
                    continue;
                }
            }
            if (!isImmediateOneWay) {
                if (isImmediateOneWay = IMMEDIATE_ONEWAY.equals(intent.getName())) {
                    continue;
                }
            }
            if (!isNoManagedTransaction) {
                if (isNoManagedTransaction = NO_MANAGED_TRANSACTION.equals(intent.getName())) {
                    continue;
                }
            }
            if (!isLocalTransaction) {
                if (isLocalTransaction = LOCAL_MANAGED_TRANSACTION.equals(intent.getName())) {
                    continue;
                }
            }
            if (!asyncInvocation) {
                if (asyncInvocation = ASYNC_INVOCATION.equals(intent.getName())) {
                    continue;
                }
            }
            if (!propagatesTransaction) {
                if (propagatesTransaction = PROPAGATES_TRANSACTION.equals(intent.getName())) {
                    continue;
                }
            }
            if (NO_LISTENER.equals(intent.getName())) {
                if (!(artifact.getParent() instanceof LogicalReference)) {
                    throw new PolicyResolutionException("The noListener intent can only be specified on a reference");
                }
            }
        }
        if (isNoManagedTransaction && isTransactedOneWay) {
            throw new PolicyResolutionException("Cannot specify a one-way interaction on a component that is configured for no transaction context");
        } else if (isNoManagedTransaction && propagatesTransaction) {
            throw new PolicyResolutionException("Cannot specify propagates transaction on a component that is configured for no transaction context");
        } else if (isLocalTransaction && isTransactedOneWay) {
            throw new PolicyResolutionException("Cannot specify a transacted one-way interaction on a component that is configured for a local transaction");
        } else if (isLocalTransaction && propagatesTransaction) {
            throw new PolicyResolutionException("Cannot specify propagates transaction on a component that is configured for a local transaction context");
        }
        if (asyncInvocation && propagatesTransaction) {
            throw new PolicyResolutionException("Cannot specify propagates transaction on an async invocation");
        }
        if (isTransactedOneWay) {
            if (artifact instanceof LogicalBinding) {
                LogicalBinding binding = (LogicalBinding) artifact;
                Bindable parent = binding.getParent();
                List operations = parent.getOperations();
                for (LogicalOperation operation : operations) {
                    if (!operation.getIntents().contains(ONEWAY)) {
                        throw new PolicyResolutionException("Cannot specify transacted one-way for a request-response operation: " + parent.getUri());
                    }
                }
            } else if (artifact instanceof LogicalOperation) {
                LogicalOperation operation = (LogicalOperation) artifact;
                if (!operation.getIntents().contains(ONEWAY)) {
                    throw new PolicyResolutionException(
                            "Cannot specify transacted one-way for a request-response operation: " + operation.getParent().getUri());
                }
            }
        }
        if (isImmediateOneWay) {
            if (artifact instanceof LogicalBinding) {
                LogicalBinding binding = (LogicalBinding) artifact;
                Bindable parent = binding.getParent();
                List operations = parent.getOperations();
                for (LogicalOperation operation : operations) {
                    if (!operation.getIntents().contains(ONEWAY)) {
                        throw new PolicyResolutionException("Cannot specify immediate one-way for a request-response operation: " + parent.getUri());
                    }
                }
            } else if (artifact instanceof LogicalOperation) {
                LogicalOperation operation = (LogicalOperation) artifact;
                if (!operation.getIntents().contains(ONEWAY)) {
                    throw new PolicyResolutionException("Cannot specify immediate one-way for a request-response operation: " + operation.getParent().getUri());
                }
            }

        }
    }

    private Set getOperationPolicySets(LogicalOperation operation) {
        LogicalScaArtifact temp = operation;
        Set policySetNames = new LinkedHashSet<>();
        while (temp != null) {
            policySetNames.addAll(temp.getPolicySets());
            temp = temp.getParent();
        }
        return policySetNames;
    }

    private Set aggregateBindingPolicySets(LogicalBinding binding) {
        LogicalScaArtifact temp = binding;
        Set policySetNames = new LinkedHashSet<>();
        while (temp != null) {
            policySetNames.addAll(temp.getPolicySets());
            temp = temp.getParent();
        }
        return policySetNames;
    }

    private Set filterProvidedIntents(QName type, Set requiredIntents) {
        BindingType bindingType = policyRegistry.getDefinition(type, BindingType.class);
        if (bindingType == null) {
            // tolerate a binding type not being registered
            return Collections.emptySet();
        }
        Set mayProvidedIntents = bindingType.getMayProvide();
        Set intentsToBeProvided = new LinkedHashSet<>();
        for (Intent intent : requiredIntents) {
            if (mayProvidedIntents.contains(intent.getName())) {
                intentsToBeProvided.add(intent);
            }
        }
        return intentsToBeProvided;

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy