From 132aa8a77685ec92bc90c03f987650d275a7b639 Mon Sep 17 00:00:00 2001 From: lresende Date: Mon, 30 Sep 2013 06:59:11 +0000 Subject: 2.0.1 RC1 release tag git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1527464 13f79535-47bb-0310-9956-ffa450edef68 --- .../builder/impl/ComponentPolicyBuilderImpl.java | 650 +++++++++++++++++++++ 1 file changed, 650 insertions(+) create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java (limited to 'sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java') diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java new file mode 100644 index 0000000000..cbade8d520 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java @@ -0,0 +1,650 @@ +/* + * 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.DefaultIntent; +import org.apache.tuscany.sca.policy.DefaultingPolicySubject; +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$ $Date$ + */ +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 intents = new HashSet(); + 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 componentTypeContractBindings = new HashMap(); + 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 + * + * + * + * + * + * + * + * And were + * + * requires="intentA intentB.q1" appears on an element + * + * @param excludedIntentList + * @param intent + * @return + */ + protected boolean checkQualifiedMutualExclusion(List 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 copy = new HashSet(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 intents = new HashSet(); + 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 copy = new HashSet(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 copy = new HashSet(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. + // Some policy plugins, e.g. JSR250, add resolved policy sets + // on the fly as they read details from annotations. So check + // that policy sets are unresolved befor blowing them away with + // a warning + Set policySets = new HashSet(); + if (definitions != null) { + for (PolicySet policySet : subject.getPolicySets()) { + if (policySet.isUnresolved()){ + 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); + } + } else { + policySets.add(policySet); + } + } + } + + subject.getPolicySets().clear(); + subject.getPolicySets().addAll(policySets); + } + + protected void removeConstrainedIntents(PolicySubject subject, BuilderContext context) { + List intents = subject.getRequiredIntents(); + + // Remove the intents whose @contrains do not include the current element + ExtensionType extensionType = subject.getExtensionType(); + if(extensionType != null){ + List copy = new ArrayList(intents); + for (Intent i : copy) { + List 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){ + + // 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 ) { + // The ExtensionType on the subject only has the binding name. The one in the system + // definitions will have the mayProvide/alwaysProvides values + if (type.getType().getLocalPart().startsWith("implementation")) { + for ( ExtensionType et : context.getDefinitions().getImplementationTypes() ) { + if ( type.getType().equals(et.getType()) ) { + type = et; + } + } + } else { + for ( ExtensionType et : context.getDefinitions().getBindingTypes() ) { + if ( type.getType().equals(et.getType()) ) { + type = et; + } + } + } + } + + if ( type == null || !type.getAlwaysProvidedIntents().contains(intent) && !type.getMayProvidedIntents().contains(intent)) { + // 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 { + error(context.getMonitor(), "IntentNotSatisfiedAtBuild", subject, intent.getName(), subject.toString()); + } + } + } + } + } + + protected Set getPolicyNames(PolicySubject subject) { + if (subject == null) { + return Collections.emptySet(); + } + Set names = new HashSet(); + for (PolicySet ps : subject.getPolicySets()) { + for (PolicyExpression exp : ps.getPolicies()) { + names.add(exp.getName().getNamespaceURI()); + } + } + return names; + } + + protected boolean isQualifiedBy(Intent qualifiableIntent, Intent qualifiedIntent){ + if (qualifiedIntent.getQualifiableIntent() == qualifiableIntent){ + return true; + } else { + return false; + } + } + + // Add in default intents. This looks at the default intent map for + // the policy subject and. If none of the mutually exclusive intents are + // already present adds in the default intent. + protected void addDefaultIntents(PolicySubject subject, Object defaultSubjectObject, BuilderContext context){ + if (!(defaultSubjectObject instanceof DefaultingPolicySubject)){ + return; + } + + DefaultingPolicySubject defaultSubject = (DefaultingPolicySubject)defaultSubjectObject; + List defaultIntents = defaultSubject.getDefaultIntents(); + + for(DefaultIntent defaultIntent : defaultIntents){ + // check default intent against the intents already in the subject + boolean addDefaultIntent = true; + + // first check the intents which, if present prevent the default being applied + for (Intent mutualExclusion : defaultIntent.getMutuallyExclusiveIntents()){ + if (subject.getRequiredIntents().contains(mutualExclusion)){ + addDefaultIntent = false; + break; + } + } + + // then check that the default intent itself is not mutually exclusive + for (Intent userDefinedIntent : subject.getRequiredIntents()){ + if (!checkMutualExclusionNoError(defaultIntent.getIntent(), userDefinedIntent, context)){ + addDefaultIntent = false; + break; + } + } + + if (addDefaultIntent == true){ + subject.getRequiredIntents().add(defaultIntent.getIntent()); + } + } + } + + /** + * Same as checkMutualExclusion but doesn't throw and error on failure + */ + protected boolean checkMutualExclusionNoError(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))) { + return true; + } + + return false; + } + +} -- cgit v1.2.3