Package org.apache.tuscany.sca.builder.impl

Source Code of org.apache.tuscany.sca.builder.impl.ComponentPolicyBuilderImpl

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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.
*/

package org.apache.tuscany.sca.builder.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.namespace.QName;

import org.apache.tuscany.sca.assembly.Binding;
import org.apache.tuscany.sca.assembly.Component;
import org.apache.tuscany.sca.assembly.ComponentReference;
import org.apache.tuscany.sca.assembly.ComponentService;
import org.apache.tuscany.sca.assembly.CompositeReference;
import org.apache.tuscany.sca.assembly.CompositeService;
import org.apache.tuscany.sca.assembly.Contract;
import org.apache.tuscany.sca.assembly.EndpointReference;
import org.apache.tuscany.sca.assembly.Reference;
import org.apache.tuscany.sca.assembly.Service;
import org.apache.tuscany.sca.assembly.builder.BuilderContext;
import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint;
import org.apache.tuscany.sca.assembly.builder.Messages;
import org.apache.tuscany.sca.core.ExtensionPointRegistry;
import org.apache.tuscany.sca.definitions.Definitions;
import org.apache.tuscany.sca.monitor.Monitor;
import org.apache.tuscany.sca.policy.ExtensionType;
import org.apache.tuscany.sca.policy.Intent;
import org.apache.tuscany.sca.policy.IntentMap;
import org.apache.tuscany.sca.policy.PolicyExpression;
import org.apache.tuscany.sca.policy.PolicySet;
import org.apache.tuscany.sca.policy.PolicySubject;
import org.apache.tuscany.sca.policy.Qualifier;

/**
* A composite builder that computes policy sets based on attached intents and policy sets.
* Useful if you want to build the model without making any runtime decisions such as
* reference/services matching
*
* @version $Rev: 979479 $ $Date: 2010-07-26 23:44:10 +0100 (Mon, 26 Jul 2010) $
*/
public class ComponentPolicyBuilderImpl {

    protected BuilderExtensionPoint builders;

    public ComponentPolicyBuilderImpl(ExtensionPointRegistry registry) {
        this.builders = registry.getExtensionPoint(BuilderExtensionPoint.class);
    }

    /**
     * Report a warning.
     *
     * @param monitor
     * @param problems
     * @param message
     * @param model
     */
    protected void warning(Monitor monitor, String message, Object model, Object... messageParameters) {
        Monitor.warning(monitor, this, Messages.BUILDER_VALIDATION_BUNDLE, message, messageParameters);
    }

    /**
     * Report a error.
     *
     * @param monitor
     * @param problems
     * @param message
     * @param model
     */
    protected void error(Monitor monitor, String message, Object model, Object... messageParameters) {
        Monitor.error(monitor, this, Messages.BUILDER_VALIDATION_BUNDLE, message, messageParameters);
    }


    /**
     * Inherit the intents and policySets from the list of models
     *
     * @param policySubject - the subject to which intents will be added
     * @param intentType - choose to copy interaction or implementation intents. Null = both
     * @param ignoreExclusiveIntents - when set true mutually exclusive intents won't be copied
     * @param models - the subjects from which intents will be copied
     */
    protected void inherit(PolicySubject policySubject, Intent.Type intentType, boolean ignoreExclusiveIntents, Object... models) {
        for (Object model : models) {
            if (model instanceof PolicySubject) {
                PolicySubject subject = (PolicySubject)model;

                if (!ignoreExclusiveIntents) {
                    // The intents are merged and the exclusion check will be done after
                    for (Intent intent : subject.getRequiredIntents()) {
                        if (!policySubject.getRequiredIntents().contains(intent)){
                            if ((intent.getType() != null) && (intentType != null) ) {
                                if (intent.getType().equals(intentType)){
                                    policySubject.getRequiredIntents().add(intent);
                                }
                            } else {
                                policySubject.getRequiredIntents().add(intent);
                            }
                        }
                    }
                } else {
                    Set<Intent> intents = new HashSet<Intent>();
                    for (Intent i1 : subject.getRequiredIntents()) {
                        boolean exclusive = false;
                        for (Intent i2 : policySubject.getRequiredIntents()) {
                            if (i1.getExcludedIntents().contains(i2) || i2.getExcludedIntents().contains(i1)) {
                                exclusive = true;
                                break;
                            }
                        }
                        if (!exclusive) {
                            if (!intents.contains(i1)){
                                if (intentType != null) {
                                    if (i1.getType().equals(intentType)){
                                        intents.add(i1);
                                    }
                                } else {
                                    intents.add(i1);
                                }
                            }
                        }
                    }
                    policySubject.getRequiredIntents().addAll(intents);
                }
                //FIXME this duplicates the intents for a implementation
                //e.g <implementation.java requires="managedTransaction.local managedTransaction.local"
                //becomes twice
                //[{http://docs.oasis-open.org/ns/opencsa/sca/200912}managedTransaction.local,
                //{http://docs.oasis-open.org/ns/opencsa/sca/200912}managedTransaction.local]
                for (PolicySet policySet : subject.getPolicySets()){
                    if (!policySubject.getPolicySets().contains(policySet)){
                        policySubject.getPolicySets().add(policySet);
                    }
                }
            }
        }
    }

    protected void configure(PolicySubject subject1, PolicySubject subject2, Intent.Type intentType, BuilderContext context) {
        if (subject1 != null) {
            resolveAndCheck(subject1, context);
        }
        if (subject2 != null) {
            resolveAndCheck(subject2, context);
        }
        inherit(subject1, intentType, false, subject2);
        checkMutualExclusion(subject1, context);
    }

    protected void configure(ComponentService componentService, BuilderContext context) {
        Service service = componentService.getService();
        if (service != null) {
            configure(componentService, service, null, context);
            configureBindings(componentService, service, context);
        }
    }

    private void configureBindings(Contract componentContract, Contract componentTypeContract, BuilderContext context) {
        if (componentTypeContract == null) {
            return;
        }
        Map<String, Binding> componentTypeContractBindings = new HashMap<String, Binding>();
        for (Binding binding : componentTypeContract.getBindings()) {
            componentTypeContractBindings.put(binding.getName(), binding);
        }
        for (Binding binding : componentContract.getBindings()) {
            Binding componentTypeBinding = componentTypeContractBindings.get(binding.getName());
            if (binding instanceof PolicySubject &&
                componentTypeBinding instanceof PolicySubject) {
                configure((PolicySubject)binding, (PolicySubject)componentTypeBinding, Intent.Type.interaction, context);
            }
        }
    }

    protected void configure(ComponentReference componentReference, BuilderContext context) {
        Reference reference = componentReference.getReference();
        if (reference != null) {
            configure(componentReference, reference, null, context);
            configureBindings(componentReference, reference, context);
        }
    }

    protected void configure(CompositeService compositeService, BuilderContext context) {
        configure(compositeService, compositeService.getPromotedService(), null, context);
    }

    protected void configure(CompositeReference compositeReference, BuilderContext context) {
        for (ComponentReference reference : compositeReference.getPromotedReferences()) {
            configure(compositeReference, reference, null, context);
        }
    }

    public void configure(Component component, BuilderContext context) {
        Monitor monitor = context.getMonitor();
       
        // fix up the component type by copying all implementation level
        // interaction intents to *all* the component type services
        for (ComponentService componentService : component.getServices()) {
            monitor.pushContext("Service: " + componentService.getName());
            try {
                configure(componentService, component.getImplementation(), Intent.Type.interaction, context);
                removeConstrainedIntents(componentService, context);
            } finally {
                monitor.popContext();
            }           
        }
       
        // Inherit the intents and policySets from the componentType
        for (ComponentReference componentReference : component.getReferences()) {
            monitor.pushContext("Reference: " + componentReference.getName());
            try {
                configure(componentReference, context);
                removeConstrainedIntents(componentReference, context);
            } finally {
                monitor.popContext();
            }
        }
       
        for (ComponentService componentService : component.getServices()) {
            monitor.pushContext("Service: " + componentService.getName());
            try {
                configure(componentService, context);
                removeConstrainedIntents(componentService, context);
            } finally {
                monitor.popContext();
            }
        }
    }
   
    /**
     * Checks if any qualifiable intents of intents in an excluded intent list match
     * with a second intent. looking for the case where
     *
     *  <intent name="intentA" excludes="intentB"/>
     <intent name="intentB" >
     *      <sca:qualifier name="q1" default="true"/>
     *      <sca:qualifier name="q2" default="true"/>
     </intent>
    
     *  And were
     * 
     *  requires="intentA intentB.q1" appears on an element
     * 
     * @param excludedIntentList
     * @param intent
     * @return
     */
    protected boolean checkQualifiedMutualExclusion(List<Intent> excludedIntentList, Intent intent){
        for (Intent excludedIntent : excludedIntentList){
            if (intent.getQualifiableIntent() != null &&
                excludedIntent != null &&
                intent.getQualifiableIntent().equals(excludedIntent)){
                return true;
            }
        }
        return false;
    }   
   
    /**
     * Check if two intents are mutually exclusive
     *
     * @param i1
     * @param i2
     * @param context
     * @return
     */
    protected boolean checkMutualExclusion(Intent i1, Intent i2, BuilderContext context){
        if ((i1 != i2) &&
            (i1.getExcludedIntents().contains(i2) ||
             i2.getExcludedIntents().contains(i1) ||
             checkQualifiedMutualExclusion(i1.getExcludedIntents(), i2) ||
             checkQualifiedMutualExclusion(i2.getExcludedIntents(), i1))) {
            error(context.getMonitor(), "MutuallyExclusiveIntentsAtBuild", this, i1, i2);
            return true;
        }
       
        return false;
    }

    /**
     * Check if a single policy subject requires mutually exclusive intents
     * @param subject1 - the policy subject to check
     * @param context - context containing useful things like the monitor instance
     * @return true if the policy subject contains mutually exclusive intents
     */
    protected boolean checkMutualExclusion(PolicySubject subject1, BuilderContext context) {
        if (subject1 == null) {
            return false;
        }
        for (Intent i1 : subject1.getRequiredIntents()) {
            for (Intent i2 : subject1.getRequiredIntents()) {
                if (checkMutualExclusion(i1, i2, context)){
                    return true;
                }             
            }
        }
        return false;
    }

    /**
     * Check if two policy subjects requires mutually exclusive intents
     * @param subject1
     * @param subject2
     * @param monitor
     * @return
     */
    protected boolean checkMutualExclusion(PolicySubject subject1, PolicySubject subject2, BuilderContext context) {
        if (subject1 == subject2 || subject1 == null || subject2 == null) {
            return false;
        }
        for (Intent i1 : subject1.getRequiredIntents()) {
            for (Intent i2 : subject2.getRequiredIntents()) {
                if (checkMutualExclusion(i1, i2, context)){
                    return true;
                }              
            }
        }
        return false;
    }

    protected boolean resolveAndCheck(PolicySubject subject, BuilderContext context) {
        if (subject == null) {
            return false;
        }
        // FIXME: [rfeng] Should we resolve the intents during the "build" phase?
        resolveAndNormalize(subject, context);
       
        checkMutualExclusion(subject, context);
           
        return false;
    }

    /**
     * Check if two names are equal
     * @param name1
     * @param name2
     * @return
     */
    protected boolean isEqual(String name1, String name2) {
        if (name1 == name2) {
            return true;
        }
        if (name1 != null) {
            return name1.equals(name2);
        } else {
            return name2.equals(name1);
        }
    }

    protected static Intent resolve(Definitions definitions, Intent proxy) {
        for (Intent i : definitions.getIntents()) {
            if (i.equals(proxy)) {
                return i;
            }
            for (Intent qi : i.getQualifiedIntents()) {
                if (qi.equals(proxy)) {
                    return qi;
                }
            }
        }
        return null;
    }

    // Replace qualifiable intents with their default qualifier. This can't be done until
    // after inheritance.
    protected void expandDefaultIntents(PolicySubject subject, BuilderContext context) {
     
        Set<Intent> copy = new HashSet<Intent>(subject.getRequiredIntents());
        for (Intent i : copy) {
            if (i.getDefaultQualifiedIntent() != null) {
                subject.getRequiredIntents().remove(i);
                subject.getRequiredIntents().add(i.getDefaultQualifiedIntent());
            }
        }      
    }
    protected void resolveAndNormalize(PolicySubject subject, BuilderContext context) {
        Definitions definitions = context.getDefinitions();
        Set<Intent> intents = new HashSet<Intent>();
        if (definitions != null) {
            for (Intent i : subject.getRequiredIntents()) {
                Intent resolved = resolve(definitions, i);
                if (resolved != null) {
                    intents.add(resolved);
                } else {
                    error(context.getMonitor(), "IntentNotFoundAtBuild", subject, i);
                    // Intent cannot be resolved
                }
            }
        }

        // Replace profile intents with their required intents
        while (!intents.isEmpty()) {
            boolean profileIntentsFound = false;
            Set<Intent> copy = new HashSet<Intent>(intents);
            for (Intent i : copy) {
                if (!i.getRequiredIntents().isEmpty()) {
                    intents.remove(i);
                    intents.addAll(i.getRequiredIntents());
                    profileIntentsFound = true;
                }
            }
            if (!profileIntentsFound) {
                // No more profileIntents
                break;
            }
        }
       
        // Replace unqualified intents if there is a qualified intent in the list
        Set<Intent> copy = new HashSet<Intent>(intents);
        for (Intent i : copy) {
            if (i.getQualifiableIntent() != null) {
                intents.remove(i.getQualifiableIntent());
            }

        }


        subject.getRequiredIntents().clear();
        subject.getRequiredIntents().addAll(intents);

        // TUSCANY-3503 - policy sets now only applied through direct
        //                or external attachement
        // resolve policy set names that have been specified for the
        // policy subject against the real policy sets from the
        // definitions files
        Set<PolicySet> policySets = new HashSet<PolicySet>();
        if (definitions != null) {
            for (PolicySet policySet : subject.getPolicySets()) {
                int index = definitions.getPolicySets().indexOf(policySet);
                if (index != -1) {
                    policySets.add(definitions.getPolicySets().get(index));
                } else {
                    // PolicySet cannot be resolved
                    warning(context.getMonitor(), "PolicySetNotFoundAtBuild", subject, policySet);
                }
            }
        }
       
        subject.getPolicySets().clear();
        subject.getPolicySets().addAll(policySets);
    }
   
    protected void removeConstrainedIntents(PolicySubject subject, BuilderContext context) {
        List<Intent> intents = subject.getRequiredIntents();
       
        // Remove the intents whose @contrains do not include the current element
        ExtensionType extensionType = subject.getExtensionType();
        if(extensionType != null){
            List<Intent> copy = new ArrayList<Intent>(intents);
            for (Intent i : copy) {
              List<ExtensionType> constrainedTypes = i.getConstrainedTypes();
              if (( constrainedTypes.size() == 0 ) && ( i.getQualifiableIntent() != null ) ) 
                constrainedTypes = i.getQualifiableIntent().getConstrainedTypes();
             
                if (constrainedTypes.size() > 0){
                    boolean constraintFound = false;
                    for (ExtensionType constrainedType : constrainedTypes){
                        if (constrainedType.getType().equals(extensionType.getType()) ||
                            constrainedType.getType().equals(extensionType.getBaseType())){
                            constraintFound = true;
                            break;
                        }
                    }
                    if(!constraintFound){
                        intents.remove(i);
                    }
                }
            }
        }
    }
   
    protected void checkIntentsResolved(PolicySubject subject, BuilderContext context) {
        // find the policy sets that satisfy the intents that are now
        // attached to the policy subject. From the OASIS policy
        // spec CD02 rev7:
        //  1272 A policySet provides an intent if any of the statements are true:
        //  1273 1. The intent is contained in the policySet @provides list.
        //  1274 2. The intent is a qualified intent and the unqualified form of the intent is contained in the policySet
        //  1275 @provides list.
        //  1276 3. The policySet @provides list contains a qualified form of the intent (where the intent is qualifiable).
        for (Intent intent : subject.getRequiredIntents()) {
            boolean intentMatched = false;
           
            loop: for (PolicySet ps : subject.getPolicySets()) {
                // FIXME: We will have to check the policy references and intentMap too
                // as well as the appliesTo
                if (ps.getProvidedIntents().contains(intent)) {
                    intentMatched = true;
                    break;
                }
               
                for (Intent psProvidedIntent : ps.getProvidedIntents()){
                    if (isQualifiedBy(psProvidedIntent, intent)){
                        intentMatched = true;
                        break loop;
                    }
                }
               
                for (IntentMap map : ps.getIntentMaps()) {
                    for (Qualifier q : map.getQualifiers()) {
                        if (intent.equals(q.getIntent())) {
                            intentMatched = true;
                            break loop;
                        }
                    }
                }
            }
           
            if (!intentMatched){             
             
              // Reference side intents can still be resolved by the service binding, so we can only issue a
              // warning here.
              if ( subject instanceof EndpointReference ) {
                 warning(context.getMonitor(), "IntentNotSatisfiedAtBuild", subject, intent.getName(), subject.toString());
              } else {
                // Need to check the ExtensionType to see if the intent is provided there. If not, throw an error
                ExtensionType type = subject.getExtensionType();

               
                if ( type == null ) {
                  error(context.getMonitor(), "IntentNotSatisfiedAtBuild", subject, intent.getName(), subject.toString());
                } else {
                  // The ExtensionType on the subject only has the binding name. The one in the system
                  // definitions will have the mayProvide/alwaysProvides values
                  for ( ExtensionType et : context.getDefinitions().getBindingTypes() ) {
                    if ( type.getType().equals(et.getType()) ) {
                      type = et;
                    }
                  }
               
                  if ( !type.getAlwaysProvidedIntents().contains(intent) && !type.getMayProvidedIntents().contains(intent)) {                               
                    error(context.getMonitor(), "IntentNotSatisfiedAtBuild", subject, intent.getName(), subject.toString());
                  }
                }
              }
            }
        }
    }

    protected Set<QName> getPolicyNames(PolicySubject subject) {
        if (subject == null) {
            return Collections.emptySet();
        }
        Set<QName> names = new HashSet<QName>();
        for (PolicySet ps : subject.getPolicySets()) {
            for (PolicyExpression exp : ps.getPolicies()) {
                names.add(exp.getName());
            }
        }
        return names;
    }
   
    protected boolean isQualifiedBy(Intent qualifiableIntent, Intent qualifiedIntent){
        if (qualifiedIntent.getQualifiableIntent() == qualifiableIntent){
            return true;
        } else {
            return false;
        }
    }

}
TOP

Related Classes of org.apache.tuscany.sca.builder.impl.ComponentPolicyBuilderImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.