All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fabric3.fabric.instantiator.LogicalModelInstantiatorImpl Maven / Gradle / Ivy

/*
* Fabric3
* Copyright (c) 2009-2011 Metaform Systems
*
* Fabric3 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version, with the
* following exception:
*
* Linking this software statically or dynamically with other
* modules is making a combined work based on this software.
* Thus, the terms and conditions of the GNU General Public
* License cover the whole combination.
*
* As a special exception, the copyright holders of this software
* give you permission to link this software with independent
* modules to produce an executable, regardless of the license
* terms of these independent modules, and to copy and distribute
* the resulting executable under terms of your choice, provided
* that you also meet, for each linked independent module, the
* terms and conditions of the license of that module. An
* independent module is a module which is not derived from or
* based on this software. If you modify this software, you may
* extend this exception to your version of the software, but
* you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version.
*
* Fabric3 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the
* GNU General Public License along with Fabric3.
* If not, see .
*/
package org.fabric3.fabric.instantiator;

import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.xml.namespace.QName;

import org.osoa.sca.annotations.Reference;
import org.w3c.dom.Document;

import org.fabric3.host.Namespaces;
import org.fabric3.model.type.component.ComponentDefinition;
import org.fabric3.model.type.component.Composite;
import org.fabric3.model.type.component.CompositeImplementation;
import org.fabric3.model.type.component.Implementation;
import org.fabric3.model.type.component.Include;
import org.fabric3.model.type.component.Property;
import org.fabric3.model.type.component.ResourceDefinition;
import org.fabric3.spi.model.instance.LogicalChannel;
import org.fabric3.spi.model.instance.LogicalComponent;
import org.fabric3.spi.model.instance.LogicalCompositeComponent;
import org.fabric3.spi.model.instance.LogicalProperty;
import org.fabric3.spi.model.instance.LogicalResource;

/**
 * @version $Rev: 10061 $ $Date: 2011-03-05 22:47:21 +0000 (Sat, 05 Mar 2011) $
 */
public class LogicalModelInstantiatorImpl implements LogicalModelInstantiator {
    /**
     * Represents a synthetic composite. Synthetic composites are created to instantiate multiple deployable composites in a single operation.
     */
    private static final QName SYNTHETIC_COMPOSITE = new QName(Namespaces.F3, "SyntheticComposite");

    private ChannelInstantiator channelInstantiator;
    private PromotionNormalizer promotionNormalizer;
    private AtomicComponentInstantiator atomicComponentInstantiator;
    private CompositeComponentInstantiator compositeComponentInstantiator;
    private WireInstantiator wireInstantiator;
    private AutowireNormalizer autowireNormalizer;
    private PromotionResolutionService promotionResolutionService;
    private AutowireInstantiator autowireInstantiator;

    public LogicalModelInstantiatorImpl(@Reference CompositeComponentInstantiator compositeComponentInstantiator,
                                        @Reference AtomicComponentInstantiator atomicComponentInstantiator,
                                        @Reference WireInstantiator wireInstantiator,
                                        @Reference AutowireInstantiator autowireInstantiator,
                                        @Reference ChannelInstantiator channelInstantiator,
                                        @Reference PromotionNormalizer promotionNormalizer,
                                        @Reference AutowireNormalizer autowireNormalizer,
                                        @Reference PromotionResolutionService promotionResolutionService) {
        this.channelInstantiator = channelInstantiator;
        this.promotionNormalizer = promotionNormalizer;
        this.atomicComponentInstantiator = atomicComponentInstantiator;
        this.compositeComponentInstantiator = compositeComponentInstantiator;
        this.wireInstantiator = wireInstantiator;
        this.autowireNormalizer = autowireNormalizer;
        this.promotionResolutionService = promotionResolutionService;
        this.autowireInstantiator = autowireInstantiator;
    }

    public InstantiationContext include(Composite composite, LogicalCompositeComponent domain) {
        return include(domain, composite, false);
    }

    public InstantiationContext include(List composites, LogicalCompositeComponent domain) {
        Composite composite = synthesizeComposite(composites);
        return include(domain, composite, true);
    }

    private InstantiationContext include(LogicalCompositeComponent domain, Composite composite, boolean synthetic) {
        InstantiationContext context = new InstantiationContext();

        // merge the property values into the parent
        includeProperties(composite, domain, context);

        // merge resources
        includeResources(composite, domain, synthetic);

        // instantiate all the components in the composite and add them to the parent
        List> newComponents = instantiate(composite, domain, synthetic, context);

        // normalize autowire settings and bindings for each new component - this must come before resolution since target URIs may be inherited
        for (LogicalComponent component : newComponents) {
            normalize(component, context);
        }

        // resolve services and references - evaluate all references since reinjection may apply
        for (LogicalComponent component : domain.getComponents()) {
            promotionResolutionService.resolve(component, context);
            autowireInstantiator.instantiate(component, context);
        }
        return context;
    }

    private void includeProperties(Composite composite, LogicalCompositeComponent domain, InstantiationContext context) {
        for (Property property : composite.getProperties().values()) {
            String name = property.getName();
            if (domain.getAllProperties().containsKey(name)) {
                URI parentUri = domain.getUri();
                URI contributionUri = domain.getDefinition().getContributionUri();
                DuplicateProperty error = new DuplicateProperty(name, parentUri, contributionUri);
                context.addError(error);
            } else {
                Document value = property.getDefaultValue();
                boolean many = property.isMany();
                LogicalProperty logicalProperty = new LogicalProperty(name, value, many, domain);
                domain.setProperties(logicalProperty);
            }
        }
    }

    private void includeResources(Composite composite, LogicalCompositeComponent domain, boolean synthetic) {
        if (synthetic) {
            for (Include include : composite.getIncludes().values()) {
                Composite included = include.getIncluded();
                for (ResourceDefinition definition : included.getResources()) {
                    LogicalResource resource = new LogicalResource(definition, domain);
                    resource.setDeployable(included.getName());
                    domain.addResource(resource);
                }
            }
        } else {
            for (ResourceDefinition definition : composite.getResources()) {
                LogicalResource resource = new LogicalResource(definition, domain);
                resource.setDeployable(composite.getName());
                domain.addResource(resource);
            }
        }
    }

    /**
     * Instantiates a composite and its children in a domain
     *
     * @param composite the composite definition to instantiate
     * @param domain    the domain logical components
     * @param synthetic true if the composite is synthetic and its children should be treated as a single deployment unit
     * @param context   the instantiation context
     * @return the newly instantiated domain-level components
     */
    private List> instantiate(Composite composite,
                                                  LogicalCompositeComponent domain,
                                                  boolean synthetic,
                                                  InstantiationContext context) {
        // instantiate the declared components
        Collection>> definitions = composite.getDeclaredComponents().values();
        List> newComponents = new ArrayList>(definitions.size());
        for (ComponentDefinition> definition : definitions) {
            LogicalComponent logicalComponent = instantiate(definition, domain, context);
            setDeployable(logicalComponent, composite.getName());
            newComponents.add(logicalComponent);
        }

        // instantiate the included components
        instantiateIncludes(composite, newComponents, synthetic, domain, context);

        // instantiate wires - note this must be done after the included components as wire targets may resolve to an included service
        wireInstantiator.instantiateCompositeWires(composite, domain, context);
        for (LogicalComponent component : newComponents) {
            wireInstantiator.instantiateReferenceWires(component, context);
        }

        // instantiate channels
        if (synthetic) {
            for (Include include : composite.getIncludes().values()) {
                // If it is a synthetic composite, included composites are the deployables.
                // Synthetic composites are used to deploy multiple composites as a group. They include the composites (deployables).
                // Adding the deployable name to domain-level components allows them to be managed as a group after they are deployed.
                Composite included = include.getIncluded();
                channelInstantiator.instantiateChannels(included, domain, context);
            }
        } else {
            channelInstantiator.instantiateChannels(composite, domain, context);

        }
        return newComponents;
    }

    /**
     * Instantiates a component in the context of a parent logical composite component.
     *
     * @param definition the component definition to instantiate
     * @param parent     the parent logical composite
     * @param context    the instantiation context
     * @return the instantiated component
     */
    @SuppressWarnings("unchecked")
    private LogicalComponent instantiate(ComponentDefinition definition, LogicalCompositeComponent parent, InstantiationContext context) {
        if (definition.getImplementation() instanceof CompositeImplementation) {
            ComponentDefinition componentDefinition = (ComponentDefinition) definition;
            return compositeComponentInstantiator.instantiate(componentDefinition, parent, context);
        } else {
            ComponentDefinition> componentDefinition = (ComponentDefinition>) definition;
            return atomicComponentInstantiator.instantiate(componentDefinition, parent, context);
        }
    }

    /**
     * Instantiates components in included composites.
     *
     * @param composite     the root composite to instantiate
     * @param newComponents the collection to hold instantiated components
     * @param synthetic     true if the root composite is synthetic
     * @param domain        the domain
     * @param context       the instantiation context
     */
    private void instantiateIncludes(Composite composite,
                                     List> newComponents,
                                     boolean synthetic,
                                     LogicalCompositeComponent domain,
                                     InstantiationContext context) {
        // instantiate the included components
        for (Include include : composite.getIncludes().values()) {
            for (ComponentDefinition> definition : include.getIncluded().getComponents().values()) {
                LogicalComponent logicalComponent = instantiate(definition, domain, context);
                if (synthetic) {
                    // If it is a synthetic composite, included composites are the deployables.
                    // Synthetic composites are used to deploy multiple composites as a group. They include the composites (deployables).
                    // Adding the deployable name to domain-level components allows them to be managed as a group after they are deployed.
                    setDeployable(logicalComponent, include.getIncluded().getName());
                } else {
                    setDeployable(logicalComponent, composite.getName());
                }
                newComponents.add(logicalComponent);
                // add to the domain since includes starting from a deployable composite are "collapsed" to the domain level
                domain.addComponent(logicalComponent);
            }
        }
    }

    /**
     * Normalizes the component hierarchy by calculating autowire and promotion settings through a depth-first traversal of leaf/atomic components.
     *
     * @param component the component to normalize
     * @param context   the instantiation context
     */
    private void normalize(LogicalComponent component, InstantiationContext context) {

        autowireNormalizer.normalize(component);

        if (component instanceof LogicalCompositeComponent) {
            LogicalCompositeComponent composite = (LogicalCompositeComponent) component;
            for (LogicalComponent child : composite.getComponents()) {
                normalize(child, context);
            }
        } else {
            promotionNormalizer.normalize(component, context);
        }
    }

    /**
     * Synthesizes a composite from a collection of composites using inclusion.
     *
     * @param composites the composites to synthesize
     * @return the synthesized composite
     */
    private Composite synthesizeComposite(List composites) {
        Composite synthesized = new Composite(SYNTHETIC_COMPOSITE);
        for (Composite composite : composites) {
            Include include = new Include();
            include.setName(composite.getName());
            include.setIncluded(composite);
            synthesized.add(include);

        }
        return synthesized;
    }

    /**
     * Recursively sets the deployable composite the logical component was instantiated from.
     *
     * @param component  the logical component
     * @param deployable the deployable
     */
    private void setDeployable(LogicalComponent component, QName deployable) {
        if (component instanceof LogicalCompositeComponent) {
            LogicalCompositeComponent composite = (LogicalCompositeComponent) component;
            for (LogicalComponent child : composite.getComponents()) {
                setDeployable(child, deployable);
            }
            for (LogicalResource resource : composite.getResources()) {
                resource.setDeployable(deployable);
            }
            for (LogicalChannel channel : composite.getChannels()) {
                channel.setDeployable(deployable);
            }
        }
        component.setDeployable(deployable);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy