summaryrefslogtreecommitdiffstats
path: root/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireBuilderImpl.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/WireBuilderImpl.java')
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireBuilderImpl.java1028
1 files changed, 1028 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/WireBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireBuilderImpl.java
new file mode 100644
index 0000000000..21725fb1b1
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireBuilderImpl.java
@@ -0,0 +1,1028 @@
+/*
+ * 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;
+import org.oasisopen.sca.ServiceRuntimeException;
+
+/**
+ * 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<String, Component> components = new HashMap<String, Component>();
+ Map<String, ComponentService> componentServices = new HashMap<String, ComponentService>();
+ Map<String, ComponentReference> componentReferences = new HashMap<String, ComponentReference>();
+ 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<String, Component> components,
+ Map<String, ComponentService> componentServices,
+ Map<String, ComponentReference> 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<String, ComponentService> componentServices,
+ Map<String, ComponentReference> 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<Wire> 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
+ .isCompatibleSubset(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<String, Component> components,
+ Map<String, ComponentService> componentServices,
+ Monitor monitor) {
+
+ monitor.pushContext("Reference: " + reference.getName());
+
+ // Get reference targets
+ List<ComponentService> refTargets = getReferenceTargets(reference);
+ if (Boolean.TRUE.equals(reference.getAutowire()) && 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.isCompatibleSubset(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.Status.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.isCompatibleSubset(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.Status.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.setStatus(EndpointReference.Status.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.Status.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.setStatus(EndpointReference.Status.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.Status.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.Status.RESOLVED_BINDING);
+ }
+ 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.isCompatibleSubset(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.Status.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.setStatus(EndpointReference.Status.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.Status.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.setStatus(EndpointReference.Status.RESOLVED_BINDING);
+ reference.getEndpointReferences().add(endpointRef);
+ } // end if
+ }
+ }
+
+ monitor.popContext();
+
+ } // end method
+
+ private boolean intentsMatch(List<Intent> referenceIntents, List<Intent> serviceIntents) {
+ Set<Intent> referenceIntentSet = new HashSet<Intent>(referenceIntents);
+ Set<Intent> serviceIntentSet = new HashSet<Intent>(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<ComponentReference> 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<ComponentReference> getPromotedComponentReferences(CompositeReference compositeReference) {
+ List<ComponentReference> componentReferences = new ArrayList<ComponentReference>();
+ 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<ComponentReference> 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) {
+ throw new ServiceRuntimeException(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 (Boolean.TRUE.equals(componentReference.getAutowire())) {
+ break;
+ }
+
+ Monitor.error(monitor,
+ this,
+ Messages.ASSEMBLY_VALIDATION,
+ "TooManyReferenceTargets",
+ componentReference.getName());
+ }
+ }
+ }
+
+ }
+
+ private boolean validateMultiplicity(Multiplicity multiplicity, List<EndpointReference> 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()) {
+ // <binding.sca without a URI does not identify a target
+ if ((binding instanceof SCABinding) && (binding.getURI() == null))
+ continue;
+ // any other binding implies a target
+ // TODO Processing for other binding types
+ return true;
+ } // end for
+ return false;
+ } // end bindingsIdentifyTargets
+
+ /**
+ * Helper method which obtains a list of targets for a reference
+ * @param reference - Component reference
+ * @return - the list of targets, which will be empty if there are no targets
+ */
+ private List<ComponentService> getReferenceTargets(ComponentReference reference) {
+ List<ComponentService> 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<String, Component> 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
+ * <ul>
+ * <li>componentName
+ * <li>componentName/serviceName
+ * <li>componentName/serviceName/bindingName
+ * </ul>
+ * @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) {
+ // <componentURI>#service-binding(serviceName/bindingName)
+ uri = uri + "#service-binding(" + parts[1] + "/" + parts[2] + ")";
+ } else if (parts.length == 2) {
+ // <componentURI>#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 <reference/> of a <component/> has @autowire=true
+ * and where the <reference/> has a <binding/> child element which
+ * declares a single target service, the reference is wired only to
+ * the single service identified by the <wire/> 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