From 21b292e89b40a911e2556372c2cd57eb4c258501 Mon Sep 17 00:00:00 2001 From: rfeng Date: Tue, 1 Dec 2009 22:01:36 +0000 Subject: Start to split policy builder into two phases: implementation hierarchy and structural hierarchy git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@885961 13f79535-47bb-0310-9956-ffa450edef68 --- .../assembly/builder/BuilderExtensionPoint.java | 8 + .../builder/DefaultBuilderExtensionPoint.java | 4 + .../tuscany/sca/assembly/impl/ExtensionImpl.java | 2 +- .../sca/builder/impl/ComponentBuilderImpl.java | 42 +- .../builder/impl/ComponentPolicyBuilderImpl.java | 349 +++++++ .../impl/CompositeComponentTypeBuilderImpl.java | 27 +- .../builder/impl/EndpointReferenceBuilderImpl.java | 2 +- .../tuscany/sca/builder/impl/ModelBuilderImpl.java | 3 + .../tuscany/sca/builder/impl/WireBuilderImpl.java | 1031 ++++++++++++++++++++ .../tuscany/sca/builder/impl/WireMatcherImpl.java | 66 ++ ...tresolver.EndpointResolverFactoryExtensionPoint | 19 - 11 files changed, 1493 insertions(+), 60 deletions(-) create mode 100644 sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java create mode 100644 sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireBuilderImpl.java create mode 100644 sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireMatcherImpl.java delete mode 100644 sca-java-2.x/trunk/modules/core-spi/src/main/resources/META-INF/services/org.apache.tuscany.sca.endpointresolver.EndpointResolverFactoryExtensionPoint diff --git a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/BuilderExtensionPoint.java b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/BuilderExtensionPoint.java index ae526b92a1..cc4156e42e 100644 --- a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/BuilderExtensionPoint.java +++ b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/BuilderExtensionPoint.java @@ -19,6 +19,8 @@ package org.apache.tuscany.sca.assembly.builder; +import java.util.Collection; + import javax.xml.namespace.QName; import org.apache.tuscany.sca.assembly.Binding; @@ -115,4 +117,10 @@ public interface BuilderExtensionPoint { * @param builder */

void removePolicyBuilder(PolicyBuilder

builder); + + /** + * Get a collection of policy builders + * @return + */ + public Collection getPolicyBuilders(); } diff --git a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/DefaultBuilderExtensionPoint.java b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/DefaultBuilderExtensionPoint.java index 2d0a4b91ee..ac2bc262ff 100644 --- a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/DefaultBuilderExtensionPoint.java +++ b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/DefaultBuilderExtensionPoint.java @@ -186,6 +186,10 @@ public class DefaultBuilderExtensionPoint implements BuilderExtensionPoint, Life loadBuilders(); return (PolicyBuilder)policyBuilders.get(policyType); } + + public Collection getPolicyBuilders() { + return policyBuilders.values(); + } public void removePolicyBuilder(PolicyBuilder builder) { policyBuilders.remove(builder.getPolicyType()); diff --git a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/impl/ExtensionImpl.java b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/impl/ExtensionImpl.java index b5018c4d43..e69eb4a771 100644 --- a/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/impl/ExtensionImpl.java +++ b/sca-java-2.x/trunk/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/impl/ExtensionImpl.java @@ -25,7 +25,7 @@ import org.apache.tuscany.sca.assembly.Extension; public class ExtensionImpl implements Extension { private QName qName; private Object value; - boolean isAttribute = false; + private boolean isAttribute = false; public ExtensionImpl() { } diff --git a/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java b/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java index 77a460e7d9..a69955e113 100644 --- a/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java +++ b/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java @@ -79,6 +79,7 @@ public class ComponentBuilderImpl { protected static final QName BINDING_SCA_QNAME = new QName(SCA11_NS, BINDING_SCA); private CompositeComponentTypeBuilderImpl componentTypeBuilder; + protected ComponentPolicyBuilderImpl policyBuilder; private AssemblyFactory assemblyFactory; private SCABindingFactory scaBindingFactory; private DocumentBuilderFactory documentBuilderFactory; @@ -96,7 +97,7 @@ public class ComponentBuilderImpl { transformerFactory = modelFactories.getFactory(TransformerFactory.class); interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); - + policyBuilder = new ComponentPolicyBuilderImpl(registry); builders = registry.getExtensionPoint(BuilderExtensionPoint.class); } @@ -147,10 +148,20 @@ public class ComponentBuilderImpl { createComponentType(component, context); // configure services based on the calculated component type - configureServices(component, monitor); + configureServices(component, context); // configure services based on the calculated component type - configureReferences(component, monitor); + configureReferences(component, context); + + // Inherit the intents and policySets from the componentType + // NOTE: configureServices/configureReferences may add callback references and services + for(ComponentReference componentReference: component.getReferences()) { + policyBuilder.configure(componentReference, context); + } + for(ComponentService componentService: component.getServices()) { + policyBuilder.configure(componentService, context); + } + } finally { monitor.popContext(); } @@ -207,7 +218,8 @@ public class ComponentBuilderImpl { * * @param component */ - private void configureServices(Component component, Monitor monitor) { + private void configureServices(Component component, BuilderContext context) { + Monitor monitor = context.getMonitor(); // If the component type has services that are not described in this // component then create services for this component @@ -237,15 +249,6 @@ public class ComponentBuilderImpl { // add callback reference model objects createCallbackReference(component, componentService); - - // intents - done later in CompositePolicyBuilder - discuss with RF - //calculateIntents(componentService, - // componentTypeService); - - // policy sets - done later in CompositePolicyBuilder - discuss with RF - // calculatePolicySets(componentService, - // componentTypeService); - } } @@ -255,8 +258,9 @@ public class ComponentBuilderImpl { * * @param component */ - private void configureReferences(Component component, Monitor monitor) { - + private void configureReferences(Component component, BuilderContext context) { + Monitor monitor = context.getMonitor(); + // If the component type has references that are not described in this // component then create references for this component addReferencesFromComponentType(component, monitor); @@ -288,14 +292,6 @@ public class ComponentBuilderImpl { // add callback service model objects createCallbackService(component, componentReference); - // intents - done later in CompositePolicyBuilder - discuss with RF - // calculateIntents(componentService, - // componentTypeService); - - // policy sets - done later in CompositePolicyBuilder - discuss with RF - // calculatePolicySets(componentService, - // componentTypeService); - // Propagate autowire setting from the component down the structural // hierarchy if (componentReference.getAutowire() == null) { diff --git a/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java b/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java new file mode 100644 index 0000000000..afe694ad75 --- /dev/null +++ b/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java @@ -0,0 +1,349 @@ +/* + * 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.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.xml.namespace.QName; + +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.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.monitor.Problem; +import org.apache.tuscany.sca.monitor.Problem.Severity; +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) { + if (monitor != null) { + Problem problem = + monitor.createProblem(this.getClass().getName(), + Messages.ASSEMBLY_VALIDATION, + Severity.WARNING, + model, + message, + messageParameters); + monitor.problem(problem); + } + } + + /** + * Report a error. + * + * @param monitor + * @param problems + * @param message + * @param model + */ + protected void error(Monitor monitor, String message, Object model, Object... messageParameters) { + if (monitor != null) { + Problem problem = + monitor.createProblem(this.getClass().getName(), + Messages.ASSEMBLY_VALIDATION, + Severity.ERROR, + model, + message, + messageParameters); + monitor.problem(problem); + } + } + + /** + * Inherit the intents and policySets from the list of models + * @param intents + * @param policySets + * @param models + */ + protected void inherit(PolicySubject policySubject, Object... models) { + for (Object model : models) { + if (model instanceof PolicySubject) { + PolicySubject subject = (PolicySubject)model; + // FIXME: We should ignore the mutually exclusive intents from different levels + policySubject.getRequiredIntents().addAll(subject.getRequiredIntents()); + policySubject.getPolicySets().addAll(subject.getPolicySets()); + } + } + } + + protected void configure(PolicySubject subject1, PolicySubject subject2, BuilderContext context) { + if (subject1 != null) { + resolveAndCheck(subject1, context); + } + if (subject2 != null) { + resolveAndCheck(subject2, context); + } + inherit(subject1, subject2); + checkMutualExclusion(subject1, context); + } + + protected void configure(ComponentService componentService, BuilderContext context) { + configure(componentService, componentService.getService(), context); + } + + protected void configure(ComponentReference componentReference, BuilderContext context) { + configure(componentReference, componentReference.getReference(), context); + } + + protected void configure(CompositeService compositeService, BuilderContext context) { + configure(compositeService, compositeService.getPromotedService(), context); + } + + protected void configure(CompositeReference compositeReference, BuilderContext context) { + for (ComponentReference reference : compositeReference.getPromotedReferences()) { + configure(compositeReference, reference, context); + } + } + + /** + * Check if a single policy subject requires multually 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 ((i1 != i2) && (i1.getExcludedIntents().contains(i2) || i2.getExcludedIntents().contains(i1))) { + error(context.getMonitor(), "MutuallyExclusiveIntents", new Object[] {subject1}, i1, i2); + return true; + } + } + } + return false; + } + + /** + * Check if two policy subjects requires multually 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 (i1.getExcludedIntents().contains(i2) || i2.getExcludedIntents().contains(i1)) { + error(context.getMonitor(), "MutuallyExclusiveIntents", new Object[] {subject1, subject2}, i1, i2); + 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); + List intents = subject.getRequiredIntents(); + int size = intents.size(); + for (int i = 0; i < size; i++) { + for (int j = i + 1; j < size; j++) { + Intent i1 = intents.get(i); + Intent i2 = intents.get(j); + if (i1 != i2 && i1.getExcludedIntents().contains(i2) || i2.getExcludedIntents().contains(i1)) { + error(context.getMonitor(), "MutuallyExclusiveIntents", subject, i1, i2); + return true; + } + } + } + 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 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; + } + + 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 { + warning(context.getMonitor(), "IntentNotFound", 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; + } + } + + // Remove the intents whose @contraints do not include the current element + // 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()); + } + } + + // Replace qualifiable intents with the default qualified intent + copy = new HashSet(intents); + for (Intent i : copy) { + if (i.getDefaultQualifiedIntent() != null) { + intents.remove(i); + intents.add(i.getDefaultQualifiedIntent()); + } + } + + subject.getRequiredIntents().clear(); + subject.getRequiredIntents().addAll(intents); + + Set policySets = new HashSet(); + 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(), "PolicySetNotFound", subject, policySet); + } + } + } + + for (Intent intent : subject.getRequiredIntents()) { + loop: for (PolicySet ps : definitions.getPolicySets()) { + // FIXME: We will have to check the policy references and intentMap too + // as well as the appliesTo + if (ps.getProvidedIntents().contains(intent)) { + policySets.add(ps); + break; + } + for (IntentMap map : ps.getIntentMaps()) { + for (Qualifier q : map.getQualifiers()) { + if (intent.equals(q.getIntent())) { + policySets.add(ps); + break loop; + } + } + } + } + } + + subject.getPolicySets().clear(); + subject.getPolicySets().addAll(policySets); + + } + + 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()); + } + } + return names; + } + +} diff --git a/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java b/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java index 115d81147b..ef569222ae 100644 --- a/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java +++ b/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java @@ -137,10 +137,10 @@ public class CompositeComponentTypeBuilderImpl { indexComponentsServicesAndReferences(composite, components, componentServices, componentReferences); // services - calculateServices(composite, components, componentServices, monitor); + calculateServices(composite, components, componentServices, context); // references - calculateReferences(composite, components, componentReferences, monitor); + calculateReferences(composite, components, componentReferences, context); // properties // Properties on the composite component are unaffected by properties @@ -215,7 +215,9 @@ public class CompositeComponentTypeBuilderImpl { private void calculateServices(ComponentType componentType, Map components, Map componentServices, - Monitor monitor) { + BuilderContext context) { + + Monitor monitor = context.getMonitor(); // Connect this component type's services to the // services from child components which it promotes @@ -233,11 +235,7 @@ public class CompositeComponentTypeBuilderImpl { // promote bindings calculatePromotedBindings(compositeService, promotedComponentService); - // promote intents - done later in CompositePolicyBuilder - discuss with RF - // calculatePromotedIntents(compositeService, promotedComponentService); - - // promote policy sets - done later in CompositePolicyBuilder - discuss with RF - // calculatePromotedPolicySets(compositeService, promotedComponentService); + componentBuilder.policyBuilder.configure(compositeService, context); } } @@ -250,8 +248,9 @@ public class CompositeComponentTypeBuilderImpl { */ private void calculateReferences(ComponentType componentType, Map components, - Map componentReferences, Monitor monitor) { - + Map componentReferences, + BuilderContext context) { + Monitor monitor = context.getMonitor(); // Connect this component type's references to the // references from child components which it promotes connectPromotedReferences(componentType, components, componentReferences, monitor); @@ -271,13 +270,9 @@ public class CompositeComponentTypeBuilderImpl { // Don't need to promote reference bindings as any lower level binding will // already be targeting the correct service without need for promotion //calculatePromotedBindings(compositeReference, promotedComponentReference); - - // promote intents - done later in CompositePolicyBuilder - discuss with RF - // calculatePromotedIntents(compositeService, promotedComponentService); - - // promote policy sets - done later in CompositePolicyBuilder - discuss with RF - // calculatePromotedPolicySets(compositeService, promotedComponentService); } + + componentBuilder.policyBuilder.configure(compositeReference, context); } } diff --git a/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointReferenceBuilderImpl.java b/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointReferenceBuilderImpl.java index be55be3bbe..30babcc08c 100644 --- a/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointReferenceBuilderImpl.java +++ b/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointReferenceBuilderImpl.java @@ -424,7 +424,7 @@ public class EndpointReferenceBuilderImpl { targetComponentService, targetBinding, true)); - endpointRef.setStatus(EndpointReference.WIRED_TARGET_NOT_FOUND); + endpointRef.setStatus(EndpointReference.WIRED_TARGET_FOUND_AND_MATCHED); // relying on the registry here to resolve the real endpoint reference.getEndpointReferences().add(endpointRef); diff --git a/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ModelBuilderImpl.java b/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ModelBuilderImpl.java index 35d5dabd87..20c6ccc3fb 100644 --- a/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ModelBuilderImpl.java +++ b/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ModelBuilderImpl.java @@ -128,6 +128,9 @@ public class ModelBuilderImpl implements CompositeBuilder { // relies on the endpoints and endpoint references having been calculated composite = compositePolicyBuilder.build(composite, context); + // FIXME [rfeng] We'll have to add a wire builder which depends on the policies to match + // endpoint references to endpoints + // For debugging - in success cases //System.out.println(dumpBuiltComposite(composite)); diff --git a/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireBuilderImpl.java b/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireBuilderImpl.java new file mode 100644 index 0000000000..46524fab0e --- /dev/null +++ b/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireBuilderImpl.java @@ -0,0 +1,1031 @@ +/* + * 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.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +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.Composite; +import org.apache.tuscany.sca.assembly.CompositeReference; +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.SCABinding; +import org.apache.tuscany.sca.assembly.Wire; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.assembly.builder.Messages; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.policy.Intent; + +/** + * Creates endpoint reference models. + */ +public class WireBuilderImpl { + + private AssemblyFactory assemblyFactory; + private InterfaceContractMapper interfaceContractMapper; + + public WireBuilderImpl(ExtensionPointRegistry registry) { + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); + } + + /** + * Create endpoint references for all component references. + * + * @param composite + */ + public Composite build(Composite composite, BuilderContext context) + throws CompositeBuilderException { + Monitor monitor = context.getMonitor(); + + // process component references + processComponentReferences(composite, monitor); + + // validate component references + validateComponentReferences(composite, monitor); + + return composite; + } + + private void processComponentReferences(Composite composite, Monitor monitor) { + + monitor.pushContext("Composite: " + composite.getName().toString()); + try { + // Index components, services and references + Map components = new HashMap(); + Map componentServices = new HashMap(); + Map componentReferences = new HashMap(); + indexComponentsServicesAndReferences(composite, components, componentServices, componentReferences); + + // Connect component references as described in wires + connectWires(composite, componentServices, componentReferences, monitor); + + // create endpoint references for each component's references + for (Component component : composite.getComponents()) { + monitor.pushContext("Component: " + component.getName()); + + try { + + // recurse for composite implementations + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + processComponentReferences((Composite)implementation, monitor); + } + + // create endpoint references to represent the component reference + for (ComponentReference reference : component.getReferences()) { + createReferenceEndpointReferences(composite, + component, + reference, + components, + componentServices, + monitor); + + // fix up links between endpoints and endpoint references that represent callbacks + for (ComponentService service : component.getServices()) { + if ((service.getInterfaceContract() != null) && (service.getInterfaceContract() + .getCallbackInterface() != null)) { + if (reference.getName().equals(service.getName())) { + for (Endpoint endpoint : service.getEndpoints()) { + endpoint.getCallbackEndpointReferences().addAll(reference + .getEndpointReferences()); + } + break; + } // end if + } // end if + } // end for + + // push down endpoint references into the leaf component references + // in the case where this component reference promotes a reference from + // a composite implementation + pushDownEndpointReferences(composite, + component, + reference, + monitor); + + } // end for + + // Validate that references are wired or promoted, according + // to their multiplicity. This validates as we go and catches cases + // where a reference has been configured directly incorrectly with its + // immediate multiplicity setting. We re-run this validation again later + // to catch to more complex cases where reference promotion causes + // multiplicity errors. + validateReferenceMultiplicity(composite, component, monitor); + + } finally { + monitor.popContext(); + } + } // end for + + } finally { + monitor.popContext(); + } + + } // end method processCompoenntReferences + + + /** + * The validate stage is separate from the process stage as enpoint references are + * pushed down the hierarchy. We don't know the full set of endpoint references until + * all processing is complete. Hence we can't validate as we go + * + * @param composite + * @param monitor + */ + private void validateComponentReferences(Composite composite, Monitor monitor) { + + monitor.pushContext("Composite: " + composite.getName().toString()); + try { + // create endpoint references for each component's references + for (Component component : composite.getComponents()) { + monitor.pushContext("Component: " + component.getName()); + + try { + + // recurse for composite implementations + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + validateComponentReferences((Composite)implementation, monitor); + } + // Validate that references are wired or promoted, according + // to their multiplicity + validateReferenceMultiplicity(composite, component, monitor); + + } finally { + monitor.popContext(); + } + } + + } finally { + monitor.popContext(); + } + + } + + protected void indexComponentsServicesAndReferences(Composite composite, + Map components, + Map componentServices, + Map componentReferences) { + + for (Component component : composite.getComponents()) { + + // Index components by name + components.put(component.getName(), component); + + ComponentService nonCallbackService = null; + int nonCallbackServices = 0; + for (ComponentService componentService : component.getServices()) { + + // Index component services by component name / service name + String uri = component.getName() + '/' + componentService.getName(); + componentServices.put(uri, componentService); + + // count how many non-callback services there are + // if there is only one the component name also acts as the + // service name + if (!componentService.isForCallback()) { + // Check how many non callback non-promoted services we have + if (nonCallbackServices == 0) { + nonCallbackService = componentService; + } + nonCallbackServices++; + } + } + + if (nonCallbackServices == 1) { + // If we have a single non callback service, index it by + // component name as well + componentServices.put(component.getName(), nonCallbackService); + } + + // Index references by component name / reference name + for (ComponentReference componentReference : component.getReferences()) { + String uri = component.getName() + '/' + componentReference.getName(); + componentReferences.put(uri, componentReference); + } + } + } + + /** + * Resolve wires and connect the sources to their targets + * + * @param composite + * @param componentServices + * @param componentReferences + * @param problems + */ + private void connectWires(Composite composite, + Map componentServices, + Map componentReferences, + Monitor monitor) { + + // For each wire, resolve the source reference, the target service, and + // add it to the list of targets of the reference + List wires = composite.getWires(); + for (int i = 0, n = wires.size(); i < n; i++) { + Wire wire = wires.get(i); + + ComponentReference resolvedReference; + ComponentService resolvedService; + + // Resolve the source reference + ComponentReference source = wire.getSource(); + if (source != null && source.isUnresolved()) { + resolvedReference = componentReferences.get(source.getName()); + if (resolvedReference != null) { + wire.setSource(resolvedReference); + } else { + Monitor.warning(monitor, this, Messages.ASSEMBLY_VALIDATION, "WireSourceNotFound", source + .getName()); + } + } else { + resolvedReference = wire.getSource(); + } + + // Resolve the target service + ComponentService target = wire.getTarget(); + if (target != null && target.isUnresolved()) { + resolvedService = componentServices.get(target.getName()); + if (resolvedService != null) { + wire.setTarget(target); + } else { + Monitor.warning(monitor, this, Messages.ASSEMBLY_VALIDATION, "WireTargetNotFound", target + .getName()); + } + } else { + resolvedService = wire.getTarget(); + } + + // Add the target service to the list of targets of the + // reference + if (resolvedReference != null && resolvedService != null) { + // Check that the target component service provides + // a superset of + // the component reference interface + if (resolvedReference.getInterfaceContract() == null || interfaceContractMapper + .isCompatible(resolvedReference.getInterfaceContract(), resolvedService.getInterfaceContract())) { + + //resolvedReference.getTargets().add(resolvedService); + if (wire.isReplace()) { + resolvedReference.getTargets().clear(); + } + resolvedReference.getTargets().add(wire.getTarget()); + } else { + Monitor.warning(monitor, this, Messages.ASSEMBLY_VALIDATION, "WireIncompatibleInterface", source + .getName(), target.getName()); + } + } + } + + // Clear the list of wires + composite.getWires().clear(); + } + + private void createReferenceEndpointReferences(Composite composite, + Component component, + ComponentReference reference, + Map components, + Map componentServices, + Monitor monitor) { + + monitor.pushContext("Reference: " + reference.getName()); + + // Get reference targets + List refTargets = getReferenceTargets(reference); + if (reference.getAutowire() == Boolean.TRUE && reference.getTargets().isEmpty()) { + + // Find suitable targets in the current composite for an + // autowired reference + Multiplicity multiplicity = reference.getMultiplicity(); + for (Component targetComponent : composite.getComponents()) { + + // Tuscany specific selection of the first autowire reference + // when there are more than one (ASM_60025) + if ((multiplicity == Multiplicity.ZERO_ONE || multiplicity == Multiplicity.ONE_ONE) && (reference + .getEndpointReferences().size() != 0)) { + break; + } + + // Prevent autowire connecting to self + if (targetComponent == component) + continue; + + for (ComponentService targetComponentService : targetComponent.getServices()) { + if (reference.getInterfaceContract() == null || interfaceContractMapper.isCompatible(reference + .getInterfaceContract(), targetComponentService.getInterfaceContract())) { + + if (intentsMatch(reference.getRequiredIntents(), targetComponentService.getRequiredIntents())) { + EndpointReference endpointRef = createEndpointRef(component, reference, false); + endpointRef.setTargetEndpoint(createEndpoint(targetComponent, targetComponentService, true)); + endpointRef.setStatus(EndpointReference.WIRED_TARGET_FOUND_READY_FOR_MATCHING); + reference.getEndpointReferences().add(endpointRef); + + // Stop with the first match for 0..1 and 1..1 references + if (multiplicity == Multiplicity.ZERO_ONE || multiplicity == Multiplicity.ONE_ONE) { + break; + } // end if + } + + } // end if + } // end for + } // end for + + if (multiplicity == Multiplicity.ONE_N || multiplicity == Multiplicity.ONE_ONE) { + if (reference.getEndpointReferences().size() == 0) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "NoComponentReferenceTarget", + reference.getName()); + } + } + + setSingleAutoWireTarget(reference); + + } else if (!refTargets.isEmpty()) { + // Check that the component reference does not mix the use of endpoint references + // specified via the target attribute with the presence of binding elements + if (bindingsIdentifyTargets(reference)) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "ReferenceEndPointMixWithTarget", + composite.getName().toString(), + component.getName(), + reference.getName()); + } + + // Resolve targets specified on the component reference + for (ComponentService target : refTargets) { + + String targetName = getComponentServiceName(target.getName()); + String bindingName = getBindingName(target.getName()); + ComponentService targetComponentService = componentServices.get(targetName); + + Component targetComponent = getComponentFromTargetName(components, targetName); + + if (targetComponentService != null) { + // Check that target component service provides a superset of the component reference interface + if (reference.getInterfaceContract() == null || interfaceContractMapper.isCompatible(reference + .getInterfaceContract(), targetComponentService.getInterfaceContract())) { + + if (bindingName != null) { + // the user has selected a binding as part of the target name + Binding targetBinding = null; + + for (Binding tmp : targetComponentService.getBindings()) { + if (tmp.getName().equals(bindingName)) { + targetBinding = tmp; + continue; + } + } + + if (targetBinding != null) { + EndpointReference endpointRef = createEndpointRef(component, reference, false); + endpointRef.setTargetEndpoint(createEndpoint(targetComponent, + targetComponentService, + targetBinding, + true)); + endpointRef.setStatus(EndpointReference.WIRED_TARGET_FOUND_AND_MATCHED); + // relying on the registry here to resolve the real endpoint + reference.getEndpointReferences().add(endpointRef); + + } else { + EndpointReference endpointRef = createEndpointRef(component, reference, true); + endpointRef.setTargetEndpoint(createEndpoint(component, targetName)); + endpointRef.setRemote(true); + endpointRef.setStatus(EndpointReference.WIRED_TARGET_NOT_FOUND); + reference.getEndpointReferences().add(endpointRef); + Monitor.warning(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "ComponentReferenceTargetNotFound", + composite.getName().toString(), + targetName); + } + + } else { + // the user hasn't selected a binding as part of the target name + + EndpointReference endpointRef = createEndpointRef(component, reference, false); + endpointRef + .setTargetEndpoint(createEndpoint(targetComponent, targetComponentService, true)); + endpointRef.setStatus(EndpointReference.WIRED_TARGET_FOUND_READY_FOR_MATCHING); + reference.getEndpointReferences().add(endpointRef); + } + } else { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "ReferenceIncompatibleInterface", + composite.getName().toString(), + component.getName() + "." + reference.getName(), + targetName); + } + } else { + // add an unresolved endpoint reference with an unresolved endpoint to go with it + EndpointReference endpointRef = createEndpointRef(component, reference, true); + endpointRef.setTargetEndpoint(createEndpoint(component, targetName)); + endpointRef.setRemote(true); + endpointRef.setStatus(EndpointReference.WIRED_TARGET_NOT_FOUND); + reference.getEndpointReferences().add(endpointRef); + Monitor.warning(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "ComponentReferenceTargetNotFound", + composite.getName().toString(), + targetName); + } // end if + } // end for + } // end if + + // if no endpoints have found so far the bindings hold the targets. + if (reference.getEndpointReferences().isEmpty()) { + for (Binding binding : reference.getBindings()) { + + String uri = binding.getURI(); + + // user hasn't put a uri on the binding so it's not a target name and the assumption is that + // the target is established via configuration of the binding element itself + if (uri == null) { + // Regular forward references are UNWIRED with no endpoint if they have an SCABinding with NO targets + // and NO URI set - but Callbacks with an SCABinding are wired and need an endpoint + if (!reference.isForCallback() && (binding instanceof SCABinding)) + continue; + + // create endpoint reference for manually configured bindings with a resolved endpoint to + // signify that this reference is pointing at some unwired endpoint + EndpointReference endpointRef = createEndpointRef(component, reference, binding, null, false); + if (binding instanceof SCABinding) { + // Assume that the system needs to resolve this binding later as + // it's the SCA binding + endpointRef.setTargetEndpoint(createEndpoint(true)); + endpointRef.setStatus(EndpointReference.NOT_CONFIGURED); + } else { + // The user has configured a binding so assume they know what + // they are doing and mark in as already resolved. + endpointRef.setTargetEndpoint(createEndpoint(false)); + endpointRef.setStatus(EndpointReference.RESOLVED_BINDING); + } + endpointRef.setRemote(true); + reference.getEndpointReferences().add(endpointRef); + continue; + } // end if + + // user might have put a local target name in the uri - see if it refers to a target we know about + // - if it does the reference binding will be matched with a service binding + // - if it doesn't it is assumed to be an external reference + if (uri.startsWith("/")) { + uri = uri.substring(1); + } + + String targetName = getComponentServiceName(uri); + String bindingName = getBindingName(uri); + + // Resolve the target component and service + ComponentService targetComponentService = componentServices.get(targetName); + Component targetComponent = getComponentFromTargetName(components, targetName); + + // If the binding URI matches a component in the composite, configure an endpoint reference with + // this component as the target. + // If not, the binding URI is assumed to reference an external service + if (targetComponentService != null) { + + // Check that the target component service provides + // a superset of the component reference interface + if (reference.getInterfaceContract() == null || interfaceContractMapper.isCompatible(reference + .getInterfaceContract(), targetComponentService.getInterfaceContract())) { + if (bindingName != null) { + // the user has selected a binding as part of the target name + Binding targetBinding = null; + + for (Binding tmp : targetComponentService.getBindings()) { + if (tmp.getName().equals(bindingName)) { + targetBinding = tmp; + continue; + } + } + + if (targetBinding != null) { + EndpointReference endpointRef = createEndpointRef(component, reference, false); + endpointRef.setTargetEndpoint(createEndpoint(targetComponent, + targetComponentService, + targetBinding, + true)); + endpointRef.setStatus(EndpointReference.WIRED_TARGET_NOT_FOUND); + // relying on the registry here to resolve the real endpoint + reference.getEndpointReferences().add(endpointRef); + + } else { + EndpointReference endpointRef = createEndpointRef(component, reference, true); + endpointRef.setTargetEndpoint(createEndpoint(component, targetName)); + endpointRef.setRemote(true); + endpointRef.setStatus(EndpointReference.WIRED_TARGET_NOT_FOUND); + reference.getEndpointReferences().add(endpointRef); + Monitor.warning(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "ComponentReferenceTargetNotFound", + composite.getName().toString(), + targetName); + } + + } else { + // create endpoint reference with dummy endpoint which will be replaced when policies + // are matched and bindings are configured later + EndpointReference endpointRef = + createEndpointRef(component, reference, binding, null, false); + endpointRef + .setTargetEndpoint(createEndpoint(targetComponent, targetComponentService, true)); + endpointRef.setStatus(EndpointReference.WIRED_TARGET_FOUND_READY_FOR_MATCHING); + reference.getEndpointReferences().add(endpointRef); + } + } else { + Monitor.warning(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "ReferenceIncompatibleInterface", + composite.getName().toString(), + reference.getName(), + uri); + } + } else { + // create endpoint reference for manually configured bindings with resolved endpoint + // to signify that this reference is pointing at some unwired endpoint. The endpoint + // is given the configured binding as a representation of the endpoint configuration. + EndpointReference endpointRef = createEndpointRef(component, reference, binding, null, false); + Endpoint endpoint = createEndpoint(false); + endpoint.setBinding(binding); + endpointRef.setTargetEndpoint(endpoint); + endpointRef.setRemote(true); + endpointRef.setStatus(EndpointReference.RESOLVED_BINDING); + reference.getEndpointReferences().add(endpointRef); + } // end if + } + } + + monitor.popContext(); + + } // end method + + private boolean intentsMatch(List referenceIntents, List serviceIntents) { + Set referenceIntentSet = new HashSet(referenceIntents); + Set serviceIntentSet = new HashSet(serviceIntents); + return referenceIntentSet.equals(serviceIntentSet); + } + + /** + * Reference targets have to be resolved in the context in which they are + * defined so they can't be push down the hierarchy during the static build. + * So we wait until we have calculated the enpoint references before pushing them + * down. Muliplicity errors will be caught by the multiplicity validation check that + * comes next + * + * @param composite + * @param component + * @param reference + * @param monitor + */ + private void pushDownEndpointReferences(Composite composite, + Component component, + ComponentReference componentReference, + Monitor monitor) { + Reference reference = componentReference.getReference(); + + if (reference instanceof CompositeReference) { + List leafComponentReferences = getPromotedComponentReferences((CompositeReference)reference); + + // for each leaf component reference copy in the endpoint references for this + // higher level (promoting) reference + // TODO - the elements are inserted starting at 0 here because the code allows references multiplicity + // validation constraints to be broken if the reference is autowire. At runtime the + // first one is chosen if max multiplicity is 1. We have an OSOA test that assumes that + // promoted references overwrite leaf references. This insert gives the same effect in the + // autowire case. We need to think about if there is a more correct answer. + for (ComponentReference leafRef : leafComponentReferences){ + int insertLocation = 0; + for (EndpointReference epr : componentReference.getEndpointReferences()){ + // copy the epr + EndpointReference eprCopy = copyHigherReference(epr, leafRef); + leafRef.getEndpointReferences().add(insertLocation, eprCopy); + insertLocation++; + } + } + } + + // TODO - what to do about callbacks in the reference promotion case + } + + /** + * Follow a reference promotion chain down to the innermost (non composite) + * component references. + * + * @param compositeReference + * @return + */ + private List getPromotedComponentReferences(CompositeReference compositeReference) { + List componentReferences = new ArrayList(); + collectPromotedComponentReferences(compositeReference, componentReferences); + return componentReferences; + } + + /** + * Follow a reference promotion chain down to the innermost (non composite) + * component references. + * + * @param compositeReference + * @param componentReferences + * @return + */ + private void collectPromotedComponentReferences(CompositeReference compositeReference, + List componentReferences) { + for (ComponentReference componentReference : compositeReference.getPromotedReferences()) { + Reference reference = componentReference.getReference(); + if (reference instanceof CompositeReference) { + + // Continue to follow the reference promotion chain + collectPromotedComponentReferences((CompositeReference)reference, componentReferences); + + } else if (reference != null) { + + // Found a non-composite reference + componentReferences.add(componentReference); + } + } + } + + /** + * Copy a higher level EndpointReference down to a lower level reference which it promotes + * @param epRef - the endpoint reference + * @param promotedReference - the promoted reference + * @return - a copy of the EndpointReference with data merged from the promoted reference + */ + private EndpointReference copyHigherReference(EndpointReference epRef, ComponentReference promotedReference) { + EndpointReference epRefClone = null; + try { + epRefClone = (EndpointReference)epRef.clone(); + } catch (Exception e) { + // Ignore (we know that EndpointReference2 can be cloned) + } // end try + // Copy across details of the inner reference + ComponentReference ref = epRefClone.getReference(); + //FIXME + epRefClone.setReference(promotedReference); + return epRefClone; + } + + private void validateReferenceMultiplicity(Composite composite, Component component, Monitor monitor) { + for (ComponentReference componentReference : component.getReferences()) { + if (!validateMultiplicity(componentReference.getMultiplicity(), + componentReference.getEndpointReferences())) { + if (componentReference.getEndpointReferences().isEmpty()) { + + // No error if the reference is promoted out of the current composite + boolean promoted = false; + for (Reference reference : composite.getReferences()) { + CompositeReference compositeReference = (CompositeReference)reference; + if (compositeReference.getPromotedReferences().contains(componentReference)) { + promoted = true; + break; + } + } + if (!promoted && !componentReference.isForCallback() && !componentReference.isWiredByImpl()) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "ReferenceWithoutTargets", + composite.getName().toString(), + componentReference.getName()); + } + } else { + // no error if reference is autowire and more targets + // than multiplicity have been found + if (componentReference.getAutowire() == Boolean.TRUE) { + break; + } + + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "TooManyReferenceTargets", + componentReference.getName()); + } + } + } + + } + + private boolean validateMultiplicity(Multiplicity multiplicity, List endpointReferences) { + + // In some tests multiplicity is not set + if (multiplicity == null) { + return true; + } + + // Count targets + int count = endpointReferences.size(); + + switch (multiplicity) { + case ZERO_N: + break; + case ZERO_ONE: + if (count > 1) { + return false; + } + break; + case ONE_ONE: + if (count != 1) { + return false; + } + break; + case ONE_N: + if (count < 1) { + return false; + } + break; + } + return true; + } + + /** + * Evaluates whether the bindings attached to a reference identify one or more target services. + * @param reference - the reference + * @return true if the bindings identify a target, false otherwise + */ + private boolean bindingsIdentifyTargets(ComponentReference reference) { + for (Binding binding : reference.getBindings()) { + // getReferenceTargets(ComponentReference reference) { + List theTargets = reference.getTargets(); + if (theTargets.isEmpty()) { + // Component reference list of targets is empty, try the implementation reference + if (reference.getReference() != null) { + theTargets = reference.getReference().getTargets(); + } // end if + } // end if + return theTargets; + } // end method getReferenceTargets + + /** + * Target names can take the form + * component/service/binding + * This extracts the component/service part + * + * @param targetName + * @return String the component/service name + */ + private String getComponentServiceName(String targetName) { + String[] parts = targetName.split("/"); + + if (parts.length > 1) { + return parts[0] + "/" + parts[1]; + } else { + return parts[0]; + } + } + + /** + * Target names can take the form + * component/service/binding + * This extracts the binding part and returns + * it. If there is no binding part it returns null + * + * @param targetName + * @return String the binding name or null if there is no binding name + */ + private String getBindingName(String targetName) { + String[] parts = targetName.split("/"); + + if (parts.length == 3) { + return parts[2]; + } else { + return null; + } + } + + /** + * Helper method that finds the Component given a target name + * @param components + * @param targetName + * @return the component + */ + private Component getComponentFromTargetName(Map components, String targetName) { + Component theComponent; + int s = targetName.indexOf('/'); + if (s == -1) { + theComponent = components.get(targetName); + } else { + theComponent = components.get(targetName.substring(0, s)); + } + return theComponent; + } // end method getComponentFromTargetName + + /** + * Helper method to create an Endpoint Reference + * @param component + * @param reference + * @param binding + * @param endpoint + * @param unresolved + * @return the endpoint reference + */ + private EndpointReference createEndpointRef(Component component, + ComponentReference reference, + Binding binding, + Endpoint endpoint, + boolean unresolved) { + EndpointReference endpointRef = createEndpointRef(component, reference, unresolved); + endpointRef.setBinding(binding); + endpointRef.setTargetEndpoint(endpoint); + return endpointRef; + } // end method + + /** + * Helper method to create an Endpoint Reference + * @param component + * @param reference + * @param unresolved + * @return the endpoint reference + */ + private EndpointReference createEndpointRef(Component component, ComponentReference reference, boolean unresolved) { + EndpointReference endpointRef = assemblyFactory.createEndpointReference(); + endpointRef.setComponent(component); + endpointRef.setReference(reference); + endpointRef.setUnresolved(unresolved); + return endpointRef; + } // end method createEndpointRef + + /** + * Helper method to create an endpoint + * @param component + * @param service + * @param unresolved + * @return the endpoint + */ + private Endpoint createEndpoint(Component component, ComponentService service, boolean unresolved) { + Endpoint endpoint = createEndpoint(unresolved); + endpoint.setComponent(component); + endpoint.setService(service); + endpoint.setUnresolved(unresolved); + return endpoint; + } // end method createEndpoint + + /** + * Helper method to create an endpoint + * @param component + * @param service + * @param binding + * @param unresolved + * @return the endpoint + */ + private Endpoint createEndpoint(Component component, ComponentService service, Binding binding, boolean unresolved) { + Endpoint endpoint = createEndpoint(unresolved); + endpoint.setComponent(component); + endpoint.setService(service); + endpoint.setBinding(binding); + endpoint.setUnresolved(unresolved); + return endpoint; + } // end method createEndpoint + + /** + * Helper method to create an Endpoint + * @param unresolved + * @return the endpoint + */ + private Endpoint createEndpoint(boolean unresolved) { + Endpoint endpoint = assemblyFactory.createEndpoint(); + endpoint.setUnresolved(unresolved); + return endpoint; + } // end method createEndpoint + + /** + * Helper method to create an Endpoint + * + * @param component The component that owns the reference + * @param targetName It can be one of the following formats + *

+ * @return the endpoint + */ + private Endpoint createEndpoint(Component component, String targetName) { + String[] parts = targetName.split("/"); + if (parts.length < 1 || parts.length > 3) { + throw new IllegalArgumentException("Invalid target URI: " + targetName); + } + + // Find the parent uri + String uri = component.getURI(); + int index = uri.lastIndexOf('/'); + if (index == -1) { + uri = ""; + } else { + uri = uri.substring(0, index); + } + + if (parts.length >= 1) { + // Append the target component name + if (uri.length() == 0) { + uri = parts[0]; + } else { + uri = uri + "/" + parts[0]; + } + } + if (parts.length == 3) { + // #service-binding(serviceName/bindingName) + uri = uri + "#service-binding(" + parts[1] + "/" + parts[2] + ")"; + } else if (parts.length == 2) { + // #service(serviceName) + uri = uri + "#service(" + parts[1] + ")"; + } + + Endpoint endpoint = assemblyFactory.createEndpoint(); + endpoint.setUnresolved(true); + endpoint.setURI(uri); + return endpoint; + } // end method createEndpoint + + /** + * ASM_5021: where a of a has @autowire=true + * and where the has a child element which + * declares a single target service, the reference is wired only to + * the single service identified by the element + */ + private void setSingleAutoWireTarget(ComponentReference reference) { + if (reference.getEndpointReferences().size() > 1 && reference.getBindings() != null + && reference.getBindings().size() == 1) { + String uri = reference.getBindings().get(0).getURI(); + if (uri != null) { + if (uri.indexOf('/') > -1) { + // TODO: must be a way to avoid this fiddling + int i = uri.indexOf('/'); + String c = uri.substring(0, i); + String s = uri.substring(i + 1); + uri = c + "#service(" + s + ")"; + } + for (EndpointReference er : reference.getEndpointReferences()) { + if (er.getTargetEndpoint() != null && uri.equals(er.getTargetEndpoint().getURI())) { + reference.getEndpointReferences().clear(); + reference.getEndpointReferences().add(er); + return; + } + } + } + } + } + +} // end class diff --git a/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireMatcherImpl.java b/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireMatcherImpl.java new file mode 100644 index 0000000000..a441d0d8c9 --- /dev/null +++ b/sca-java-2.x/trunk/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireMatcherImpl.java @@ -0,0 +1,66 @@ +/* + * 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 org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.PolicyBuilder; +import org.apache.tuscany.sca.assembly.builder.WireBuilder; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; + +/** + * + */ +public class WireMatcherImpl implements WireBuilder { + private ExtensionPointRegistry registry; + private InterfaceContractMapper interfaceContractMapper; + private BuilderExtensionPoint builderExtensionPoint; + + /** + * @param registry + */ + public WireMatcherImpl(ExtensionPointRegistry registry) { + super(); + this.registry = registry; + this.builderExtensionPoint = registry.getExtensionPoint(BuilderExtensionPoint.class); + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + this.interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + } + + public boolean build(EndpointReference endpointReference, Endpoint endpoint, BuilderContext context) { + InterfaceContract sourceIC = endpointReference.getComponentReferenceInterfaceContract(); + InterfaceContract targetIC = endpoint.getComponentServiceInterfaceContract(); + if (!interfaceContractMapper.isCompatible(sourceIC, targetIC)) { + return false; + } + for (PolicyBuilder policyBuilder : builderExtensionPoint.getPolicyBuilders()) { + if (!policyBuilder.build(endpointReference, endpoint, context)) { + return false; + } + } + return true; + } + +} diff --git a/sca-java-2.x/trunk/modules/core-spi/src/main/resources/META-INF/services/org.apache.tuscany.sca.endpointresolver.EndpointResolverFactoryExtensionPoint b/sca-java-2.x/trunk/modules/core-spi/src/main/resources/META-INF/services/org.apache.tuscany.sca.endpointresolver.EndpointResolverFactoryExtensionPoint deleted file mode 100644 index dfe7f6cdde..0000000000 --- a/sca-java-2.x/trunk/modules/core-spi/src/main/resources/META-INF/services/org.apache.tuscany.sca.endpointresolver.EndpointResolverFactoryExtensionPoint +++ /dev/null @@ -1,19 +0,0 @@ -# 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. - -org.apache.tuscany.sca.endpointresolver.DefaultEndpointResolverFactoryExtensionPoint - -- cgit v1.2.3