private boolean haveMatchingPolicy()

in modules/core/src/main/java/org/apache/tuscany/sca/core/runtime/impl/EndpointReferenceBinderImpl.java [731:1046]


    private boolean haveMatchingPolicy(EndpointReference endpointReference, Endpoint endpoint, Audit matchAudit, BuilderContext builderContext){
        matchAudit.append("Match policy of " + endpointReference.toString() + " to " + endpoint.toString() + " ");
        
        if (!endpoint.getSpecVersion().equals(Base.SCA11_NS)){
            // the thing we need to check here is asyncInvocation as only OASIS supports that
            if (endpointReference.isAsyncInvocation()){
                // this definitely won't mactch anything but OASIS so fail
                matchAudit.append("No match because the endpoint reference is configured for asyncInvocation " +
                                  "and the target endpoint is not an OASIS endpoint, specVersion = " + 
                                  endpoint.getSpecVersion());
                matchAudit.appendSeperator();
                return false;
            } else {
                // Assume it matches as we don't know how to do policy 
                // matching with anything but OASIS endpoints
                matchAudit.append("Match because the target endpoint is not an OASIS endpoint, specVersion = " + 
                                  endpoint.getSpecVersion());
                matchAudit.appendSeperator();
                return true;
            }
        }
            
        List<PolicySet> referencePolicySets = new ArrayList<PolicySet>();
        Binding binding = null;
        
        if (endpointReference.getBinding() == null){
            binding = endpoint.getBinding();
        } else {
            binding = endpointReference.getBinding();
        }
        
        // if there are any intents that are mutually exclusive between 
        // service and reference then they don't match
        for (Intent eprIntent : endpointReference.getRequiredIntents()){
            for (Intent epIntent : endpoint.getRequiredIntents()){ 
                if (eprIntent.getExcludedIntents().contains(epIntent) ||
                    epIntent.getExcludedIntents().contains(eprIntent) ||
                    checkQualifiedMutualExclusion(eprIntent.getExcludedIntents(), epIntent) ||
                    checkQualifiedMutualExclusion(epIntent.getExcludedIntents(), eprIntent)){
                    matchAudit.append("No match because the following intents are mutually exclusive " + 
                                      eprIntent.toString() +
                                      " " +
                                      epIntent.toString() +
                                      " ");
                    matchAudit.appendSeperator();
                    return false;
                }
            }
        }
        
        // Find the set of policy sets from this reference. This includes 
        // the policy sets that are specific to the service binding and 
        // any policy sets that are not binding specific    
        for (PolicySet policySet : endpointReference.getPolicySets()){
            PolicyBuilder policyBuilder = null;
            
            if (policySet.getPolicies().size() > 0){
                QName policyType = policySet.getPolicies().get(0).getName();
                policyBuilder = builders.getPolicyBuilder(policyType);
            }
            
            if ((policyBuilder == null) ||
                (policyBuilder != null && policyBuilder.getSupportedBindings() == null) ||
                (policyBuilder != null && policyBuilder.getSupportedBindings().contains(binding.getType()))){
                referencePolicySets.add(policySet);
            }
        }
        
        // if there are no policy sets on the reference take the policy sets from the
        // service binding we are matching against
        if (referencePolicySets.isEmpty()) {
            for (PolicySet policySet : endpoint.getPolicySets()){
                PolicyBuilder policyBuilder = null;
                
                if (policySet.getPolicies().size() > 0){
                    QName policyType = policySet.getPolicies().get(0).getName();
                    policyBuilder = builders.getPolicyBuilder(policyType);
                }
                
                if ((policyBuilder == null) ||
                    (policyBuilder != null && policyBuilder.getSupportedBindings() == null) ||
                    (policyBuilder != null && policyBuilder.getSupportedBindings().contains(binding.getType()))){
                    referencePolicySets.add(policySet);
                }
            }   
        }
        
        // the "appliesTo" algorithm to remove any policy sets that 
        // don't apply to the service binding will already have been 
        // run during the build phase
        
        // Determine if there are any reference policies
        boolean noEndpointReferencePolicies = true;
        
        for (PolicySet policySet : referencePolicySets){
            if (policySet.getPolicies().size() > 0){
                noEndpointReferencePolicies = false;
                break;
            }
        }
        
        // Determine of there are any service policies
        boolean noEndpointPolicies = true;
        
        for (PolicySet policySet : endpoint.getPolicySets()){
            if (policySet.getPolicies().size() > 0){
                noEndpointPolicies = false;
                break;
            }
        }        
        
        // if no policy sets or intents are present then they match
        if ((endpointReference.getRequiredIntents().size() == 0) &&
            (endpoint.getRequiredIntents().size() == 0) &&
            (noEndpointReferencePolicies) &&
            (noEndpointPolicies)) {
            matchAudit.append("Match because there are no intents or policies ");
            matchAudit.appendSeperator();
            return true;
        }        
        
        // check that the intents on the reference side are resolved 
        // can't do this until this point as the service binding
        // may come into play. Intents may be satisfied by the default
        // or optional intents that the binding type provides. Failing
        // this they must be satisfied by reference policy sets
        // Failing this the intent is unresolved and the reference and 
        // service don't match
        
        // TODO - seems that we should do this loop on a binding by binding basis
        //        rather than each time we do matching
        BindingType bindingType = null;
        
        Definitions systemDefinitions = null;
        if (builderContext != null){
            systemDefinitions = builderContext.getDefinitions();
        } else {
            if (((RuntimeEndpoint)endpoint).getCompositeContext() == null) {
                return true;
            }
            systemDefinitions = ((RuntimeEndpoint)endpoint).getCompositeContext().getSystemDefinitions();
        }
        
        bindingType = systemDefinitions.getBindingType(binding.getType());
        
        // Before we start examining intents, remove any whose constrained
        // types don't include the binding type
        removeConstrainedIntents(endpointReference, bindingType);
        
        List<Intent> eprIntents = new ArrayList<Intent>();
        List<Intent> eprMayProvideInterationIntents = new ArrayList<Intent>();
        eprIntents.addAll(endpointReference.getRequiredIntents());
        
        // first check the binding type
        for (Intent intent : endpointReference.getRequiredIntents()){ 
            if (bindingType != null && 
                bindingType.getAlwaysProvidedIntents().contains(intent)){
                eprIntents.remove(intent);
            } else if (bindingType != null &&
                       bindingType.getMayProvidedIntents().contains(intent)){
                eprIntents.remove(intent);
                if (intent.getType().equals(Intent.Type.interaction)){
                    eprMayProvideInterationIntents.add(intent);
                }
            } else {
               // TODO - this code also appears in the ComponentPolicyBuilder
               //        so should rationalize
               loop: for (PolicySet policySet : referencePolicySets){
                    if (policySet.getProvidedIntents().contains(intent)){
                        eprIntents.remove(intent);
                        break;
                    }
                    
                    for (Intent psProvidedIntent : policySet.getProvidedIntents()){
                        if (isQualifiedBy(psProvidedIntent, intent)){
                            eprIntents.remove(intent);
                            break loop;
                        }
                    }

                    for (IntentMap map : policySet.getIntentMaps()) {
                        for (Qualifier q : map.getQualifiers()) {
                            if (intent.equals(q.getIntent())) {
                                eprIntents.remove(intent);
                                break loop;
                            }
                        }
                    }                    
                }          
            }                
        }
        
        // if there are unresolved intents the service and reference don't match
        if (eprIntents.size() > 0){
            matchAudit.append("No match because there are unresolved intents " + eprIntents.toString() + " ");
            matchAudit.appendSeperator();
            return false;
        }  
        
        // TUSCANY-3959 - something that's not explicitly stated in the spec. mayProvides intents don't
        //                lead to policy sets as the binding natively implements the intent. So 
        //                we need to check that these intents match explicitly between reference and service
        //                sides
        if (eprMayProvideInterationIntents.size() > 0){
            for (Intent eprIntent : eprMayProvideInterationIntents){
                boolean match = false;
                for (Intent epIntent : endpoint.getRequiredIntents()){
                    if (epIntent.equals(eprIntent)){
                        match = true;
                        break;
                    }
                }
                
                if (!match){
                    matchAudit.append("No match because the reference has a mayProvide intent that the service doesn't have " + eprIntent.getName());
                    matchAudit.appendSeperator();
                    return false;
                }
            }
        }
        
        // if there are no policies on epr or ep side then 
        // they match
        if (noEndpointPolicies && noEndpointReferencePolicies){
            matchAudit.append("Match because the intents are resolved and there are no policy sets ");
            matchAudit.appendSeperator();
            return true;
        }
        
        // if there are some policies on one side and not the other then 
        // the don't match
        if (noEndpointPolicies && !noEndpointReferencePolicies) {
            matchAudit.append("No match because there are policy sets at the endpoint reference but not at the endpoint ");
            matchAudit.appendSeperator();
            return false;
        }
        
        if (!noEndpointPolicies && noEndpointReferencePolicies){
            matchAudit.append("No match because there are policy sets at the endpoint but not at the endpoint reference ");
            matchAudit.appendSeperator();
            return false;
        }
        
        // If policy set QNames from epr and er match exactly then the reference and 
        // service policies are compatible
        Set<PolicySet> referencePolicySet = new HashSet<PolicySet>(referencePolicySets);
        Set<PolicySet> servicePolicySet = new HashSet<PolicySet>(endpoint.getPolicySets());
        if(referencePolicySet.equals(servicePolicySet)){
            matchAudit.append("Match because the policy sets on both sides are eactly the same ");
            matchAudit.appendSeperator();
            return true;
        }
        
        // if policy set language at ep and epr are not the same then there is no
        // match. We get the policy language by looking at the first expression
        // of the first policy set. By this stage we know that all the policy sets
        // in an endpoint or endpoint reference will use a single language and we know 
        // that there is at least one policy set with at least one policy
        QName eprLanguage = null;
        
        for (PolicySet policySet : referencePolicySets){
            if (policySet.getPolicies().size() > 0){
                eprLanguage = policySet.getPolicies().get(0).getName();
                break;
            }
        }
        
        QName epLanguage = null;
          
        for (PolicySet policySet : endpoint.getPolicySets()){
            if (policySet.getPolicies().size() > 0){
                epLanguage = policySet.getPolicies().get(0).getName();
                break;
            }
        }
        
        if(!eprLanguage.getNamespaceURI().equals(epLanguage.getNamespaceURI())){
            matchAudit.append("No match because the policy sets on either side have policies in differnt languages " + 
                              eprLanguage + 
                              " and " +
                              epLanguage +
                              " ");
            matchAudit.appendSeperator();
            return false;
        }
        
        // now do a policy specific language match 
        PolicyBuilder builder = builders.getPolicyBuilder(eprLanguage);
        boolean match = false;
        
        // switch the derived list of policy sets into the reference
        // it will be left there if there is a match
        List<PolicySet> originalPolicySets = endpointReference.getPolicySets();
        endpointReference.getPolicySets().clear();
        endpointReference.getPolicySets().addAll(referencePolicySets);
        
        if (builder != null) {
            if (builderContext == null){
                builderContext = new BuilderContext(monitor);
            }
            
            match = builder.build(endpointReference, endpoint, builderContext);
        } 
                
        if (!match){
            matchAudit.append("No match because the language specific matching failed ");
            matchAudit.appendSeperator();
            endpointReference.getPolicySets().clear();
            endpointReference.getPolicySets().addAll(originalPolicySets);
        } else {
            matchAudit.append("Match because the language specific matching succeeded ");
            matchAudit.appendSeperator();
        }
        
        return match;
    }