summaryrefslogtreecommitdiffstats
path: root/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java')
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java650
1 files changed, 650 insertions, 0 deletions
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<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.
+ // 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<PolicySet> policySets = new HashSet<PolicySet>();
+ 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<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){
+
+ // 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<String> getPolicyNames(PolicySubject subject) {
+ if (subject == null) {
+ return Collections.emptySet();
+ }
+ Set<String> names = new HashSet<String>();
+ 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<DefaultIntent> 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;
+ }
+
+}