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

org.fabric3.policy.resolver.AbstractPolicyResolver 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.resolver;

import javax.xml.namespace.QName;
import java.net.URI;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

import org.fabric3.model.type.component.ComponentDefinition;
import org.fabric3.model.type.component.ComponentType;
import org.fabric3.model.type.component.Implementation;
import org.fabric3.model.type.definitions.Intent;
import org.fabric3.model.type.definitions.PolicySet;
import org.fabric3.policy.infoset.PolicyEvaluator;
import org.fabric3.spi.generator.policy.PolicyRegistry;
import org.fabric3.spi.generator.policy.PolicyResolutionException;
import org.fabric3.spi.lcm.LogicalComponentManager;
import org.fabric3.spi.model.instance.Bindable;
import org.fabric3.spi.model.instance.LogicalBinding;
import org.fabric3.spi.model.instance.LogicalChannel;
import org.fabric3.spi.model.instance.LogicalComponent;
import org.fabric3.spi.model.instance.LogicalCompositeComponent;
import org.fabric3.spi.model.instance.LogicalReference;
import org.fabric3.spi.model.instance.LogicalScaArtifact;
import org.fabric3.spi.model.instance.LogicalService;

/**
 * Base class for resolving policies.
 */
public class AbstractPolicyResolver {
    protected LogicalComponentManager lcm;
    protected PolicyEvaluator policyEvaluator;
    protected PolicyRegistry policyRegistry;

    protected AbstractPolicyResolver(PolicyRegistry policyRegistry, LogicalComponentManager lcm, PolicyEvaluator policyEvaluator) {
        this.policyRegistry = policyRegistry;
        this.lcm = lcm;
        this.policyEvaluator = policyEvaluator;
    }

    /**
     * Resolves intents to policies.
     *
     * @param intents the intents to resolve
     * @param target  the logical artifact to evaluate policy set "applies to" constraints against
     * @return the resolved policy sets
     * @throws PolicyResolutionException if there is an error during resolution
     */
    protected Set resolvePolicies(Set intents, LogicalScaArtifact target) throws PolicyResolutionException {

        Set policies = new LinkedHashSet();

        Collection definitions = policyRegistry.getAllDefinitions(PolicySet.class);
        // Calculate appliesTo by first determining if the policy set provides the intent and then matching its appliesTo expression
        // against the logical artifact given as a target
        for (PolicySet policySet : definitions) {
            Iterator iterator = intents.iterator();
            while (iterator.hasNext()) {
                Intent intent = iterator.next();
                if (policySet.doesProvide(intent.getName())) {
                    String appliesTo = policySet.getAppliesTo();
                    String attachTo = policySet.getAttachTo();
                    if ((appliesTo == null && attachTo == null) || (attachTo == null && policyEvaluator.doesApply(appliesTo, target)) || attachTo != null) {
                        policies.add(policySet);
                        iterator.remove();
                    }
                }
            }
        }
        return policies;
    }

    /**
     * Filter invalid intents.
     *
     * @param type            the type to filter on
     * @param requiredIntents the intents to filter
     * @throws PolicyResolutionException if an error is encountered filtering
     */
    protected void filterInvalidIntents(QName type, Set requiredIntents) throws PolicyResolutionException {
        for (Iterator it = requiredIntents.iterator(); it.hasNext(); ) {
            Intent intent = it.next();
            QName intentName = intent.getName();
            if (intent.getIntentType() != null) {
                if (!intent.doesConstrain(type)) {
                    it.remove();
                }
            } else {
                if (!intent.isQualified()) {
                    throw new PolicyResolutionException("Unqualified intent without constrained artifact: " + intentName);
                }
                Intent qualifiableIntent = policyRegistry.getDefinition(intent.getQualifiable(), Intent.class);
                if (qualifiableIntent == null) {
                    throw new PolicyResolutionException("Unknown intent: " + intent.getQualifiable());
                }
                if (!qualifiableIntent.doesConstrain(type)) {
                    it.remove();
                }
            }
        }

    }

    protected void filterMutuallyExclusiveIntents(Set intents) {
        if (intents.isEmpty()) {
            return;
        }
        Set removed = new HashSet();

        for (Intent current : intents) {
            if (removed.contains(current)) {
                continue;
            }
            for (Intent intent : intents) {
                if (current.getExcludes().contains(intent.getName()) || intent.getExcludes().contains(current.getName())) {

                    removed.add(intent);
                }
            }
        }
        for (Intent intent : removed) {
            intents.remove(intent);
        }
    }

    /**
     * Aggregates intents of a binding by walking the implementation and structural hierarchies of the parent.
     *
     * @param binding the binding
     * @return the aggregated intents
     */
    protected Set aggregateIntents(LogicalBinding binding) throws PolicyResolutionException {
        Bindable parent = binding.getParent();
        Set aggregatedIntents = new LinkedHashSet();

        // add binding intents
        aggregatedIntents.addAll(binding.getIntents());

        validateIntents(binding);

        if (parent instanceof LogicalReference) {
            return aggregateReferenceIntents((LogicalReference) parent, aggregatedIntents);
        } else if (parent instanceof LogicalService) {
            return aggregateServiceIntents((LogicalService) parent, aggregatedIntents);
        } else {
            // channel
            LogicalChannel channel = (LogicalChannel) parent;
            aggregatedIntents.addAll(channel.getDefinition().getIntents());
            aggregatedIntents.addAll(channel.getIntents());
            return aggregatedIntents;
        }
    }

    private void validateIntents(LogicalBinding binding) throws PolicyResolutionException {
        Set intents = policyRegistry.getDefinitions(binding.getIntents(), Intent.class);
        for (Intent current : intents) {
            for (Intent intent : intents) {
                if (current.getExcludes().contains(intent.getName())) {
                    throw new PolicyResolutionException("Mutually exclusive intents specified on binding: " + binding.getParent().getUri());
                }
            }
        }

    }

    /**
     * Aggregates intents fof a service by walking the implementation and structural hierarchies of the parent.
     *
     * @param service the service
     * @return the aggregated intents
     */
    private Set aggregateServiceIntents(LogicalService service, Set aggregatedIntents) {
        processIntents(service.getIntents(), aggregatedIntents);

        // walk the implementation and structural hierarchy of the service
        LogicalComponent parent = service.getParent();

        LogicalService currentService = service;

        while (parent != null) {
            processIntents(parent.getIntents(), aggregatedIntents);
            ComponentDefinition> definition = parent.getDefinition();
            if (definition != null) {
                processIntents(definition.getIntents(), aggregatedIntents);
                Implementation implementation = definition.getImplementation();
                if (implementation != null) {
                    processIntents(implementation.getIntents(), aggregatedIntents);
                    ComponentType componentType = implementation.getComponentType();
                    if (componentType != null) {
                        processIntents(componentType.getIntents(), aggregatedIntents);
                    }
                }
            }

            if (parent.getParent() != null && parent.getParent().getParent() == null) {
                // Special case - at the domain level the top level composite is removed during deployment. Its intents (defined in the component type) need
                // to be added to the hierarchy. This is achieved by walking the definitions.
                ComponentDefinition componentDefinition = parent.getDefinition();
                ComponentType type = componentDefinition.getParent();
                processIntents(type.getIntents(), aggregatedIntents);
            }

            if (parent instanceof LogicalCompositeComponent) {
                LogicalCompositeComponent compositeParent = (LogicalCompositeComponent) parent;
                for (LogicalService logicalService : compositeParent.getServices()) {
                    if (logicalService.getPromotedUri().equals(currentService.getUri())) {
                        processIntents(logicalService.getIntents(), aggregatedIntents);
                        currentService = logicalService;
                    }
                }
            }

            parent = parent.getParent();
        }
        return aggregatedIntents;
    }

    /**
     * Aggregates intents fof a reference by walking the implementation and structural hierarchies of the parent.
     *
     * @param reference the service
     * @return the aggregated intents
     */
    private Set aggregateReferenceIntents(LogicalReference reference, Set aggregatedIntents) {
        processIntents(reference.getIntents(), aggregatedIntents);

        // walk the implementation and structural hierarchy of the service
        LogicalComponent parent = reference.getParent();

        LogicalReference currentReference = reference;

        while (parent != null) {
            processIntents(parent.getIntents(), aggregatedIntents);

            ComponentDefinition> definition = parent.getDefinition();
            if (definition != null) {
                processIntents(definition.getIntents(), aggregatedIntents);
                Implementation implementation = definition.getImplementation();
                if (implementation != null) {
                    processIntents(implementation.getIntents(), aggregatedIntents);
                    ComponentType componentType = implementation.getComponentType();
                    if (componentType != null) {
                        processIntents(componentType.getIntents(), aggregatedIntents);
                    }
                }
            }

            if (parent.getParent() != null && parent.getParent().getParent() == null) {
                // Special case - at the domain level the top level composite is removed during deployment. Its intents (defined in the component type) need
                // to be added to the hierarchy. This is achieved by walking the definitions.
                ComponentDefinition componentDefinition = parent.getDefinition();
                ComponentType type = componentDefinition.getParent();
                processIntents(type.getIntents(), aggregatedIntents);
            }

            if (parent instanceof LogicalCompositeComponent) {
                LogicalCompositeComponent compositeParent = (LogicalCompositeComponent) parent;
                for (LogicalReference logicalReference : compositeParent.getReferences()) {
                    for (URI promotedUri : logicalReference.getPromotedUris()) {
                        if (promotedUri.equals(currentReference.getUri())) {
                            processIntents(logicalReference.getIntents(), aggregatedIntents);
                            currentReference = logicalReference;
                        }
                    }
                }
            }

            parent = parent.getParent();
        }
        return aggregatedIntents;

    }

    /**
     * Aggregate intents from ancestors of a component. Components are handled differently than other SCA artifacts as implementation intents are inherited.
     *
     * @param component the logical artifact to aggregate intents for
     * @return the aggregated intents
     */
    protected Set aggregateIntents(LogicalComponent component) {
        LogicalComponent current = component;
        Set aggregatedIntents = new LinkedHashSet();

        while (current != null) {
            Set currentIntents = current.getIntents();
            processIntents(currentIntents, aggregatedIntents);

            ComponentDefinition> definition = current.getDefinition();
            if (definition != null) {
                processIntents(definition.getIntents(), aggregatedIntents);
                Implementation implementation = definition.getImplementation();
                if (implementation != null) {
                    processIntents(implementation.getIntents(), aggregatedIntents);
                    ComponentType componentType = implementation.getComponentType();
                    if (componentType != null) {
                        processIntents(componentType.getIntents(), aggregatedIntents);
                    }
                }
            }
            current = current.getParent();
        }
        return aggregatedIntents;
    }

    /**
     * Adds the contents of the intents to the set of aggregated intents according to rules set out in the SCA policy specification
     *
     * @param intents           the intents to add
     * @param aggregatedIntents the set of aggregated intents
     */
    private void processIntents(Set intents, Set aggregatedIntents) {
        for (QName currentIntent : intents) {
            String localPart = currentIntent.getLocalPart();
            boolean exclude = false;
            String namespace = currentIntent.getNamespaceURI();
            for (Iterator iterator = aggregatedIntents.iterator(); iterator.hasNext(); ) {
                QName aggregatedIntent = iterator.next();
                if (namespace.equals(aggregatedIntent.getNamespaceURI()) && aggregatedIntent.getLocalPart().startsWith(localPart + ".")) {
                    // if the parent intent is a profile intent of a qualified intent on the child element, ignore the profile intent
                    exclude = true;
                    break;
                } else if (namespace.equals(aggregatedIntent.getNamespaceURI()) && localPart.startsWith(aggregatedIntent.getLocalPart() + ".")) {
                    // if the intent from the parent qualifies a profile intent on a child element, remove the child profile intent and add the
                    // parent qualified intent to the aggregated intents
                    iterator.remove();
                    break;
                }
            }
            if (!exclude) {
                aggregatedIntents.add(currentIntent);
            }
        }
    }

    /**
     * Resolves intents, including expanding profile intents.
     *
     * @param intentNames the intent names to resolve
     * @return the expanded intents
     * @throws PolicyResolutionException if an exception is encountered resolving the intents
     */
    protected Set resolveIntents(Set intentNames) throws PolicyResolutionException {
        Set requiredIntents = new LinkedHashSet();
        for (QName intentName : intentNames) {
            Intent intent = policyRegistry.getDefinition(intentName, Intent.class);
            if (intent == null) {
                throw new PolicyResolutionException("Unknown intent: " + intentName);
            }
            if (intent.isProfile()) {
                for (QName requiredIntentName : intent.getRequires()) {
                    Intent requiredIntent = policyRegistry.getDefinition(requiredIntentName, Intent.class);
                    if (requiredIntent == null) {
                        throw new PolicyResolutionException("Unknown intent" + requiredIntentName);
                    }
                    requiredIntents.add(requiredIntent);

                }
            } else {
                requiredIntents.add(intent);
            }
        }
        return requiredIntents;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy