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

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

The newest version!
/*
 * Fabric3
 * Copyright (c) 2009-2015 Metaform Systems
 *
 * Licensed 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.
 * Portions originally based on Apache Tuscany 2007
 * licensed under the Apache 2.0 license.
 */
package org.fabric3.fabric.domain.instantiator;

import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import org.fabric3.api.model.type.component.Component;
import org.fabric3.api.model.type.component.Composite;
import org.fabric3.api.model.type.component.Implementation;
import org.fabric3.api.model.type.component.Include;
import org.fabric3.api.model.type.component.Property;
import org.fabric3.api.model.type.component.Resource;
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;
import org.fabric3.spi.model.type.component.CompositeImplementation;
import org.oasisopen.sca.annotation.Constructor;
import org.oasisopen.sca.annotation.Reference;
import org.w3c.dom.Document;

/**
 *
 */
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(org.fabric3.api.Namespaces.F3, "SyntheticComposite");

    private ChannelInstantiator channelInstantiator;
    private AtomicComponentInstantiator atomicComponentInstantiator;
    private CompositeComponentInstantiator compositeComponentInstantiator;
    private WireInstantiator wireInstantiator;
    private AutowireInstantiator autowireInstantiator;

    @Constructor
    public LogicalModelInstantiatorImpl(@Reference CompositeComponentInstantiator compositeComponentInstantiator,
                                        @Reference AtomicComponentInstantiator atomicComponentInstantiator,
                                        @Reference WireInstantiator wireInstantiator,
                                        @Reference AutowireInstantiator autowireInstantiator,
                                        @Reference ChannelInstantiator channelInstantiator) {
        this.channelInstantiator = channelInstantiator;
        this.atomicComponentInstantiator = atomicComponentInstantiator;
        this.compositeComponentInstantiator = compositeComponentInstantiator;
        this.wireInstantiator = wireInstantiator;
        this.autowireInstantiator = autowireInstantiator;
    }

    public LogicalModelInstantiatorImpl(CompositeComponentInstantiator compositeComponentInstantiator,
                                        AtomicComponentInstantiator atomicComponentInstantiator,
                                        WireInstantiator wireInstantiator,
                                        AutowireInstantiator autowireInstantiator) {
        this(compositeComponentInstantiator, atomicComponentInstantiator, wireInstantiator, autowireInstantiator, null);
    }

    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
        instantiate(composite, domain, synthetic, context);

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

    private void includeProperties(Composite composite, LogicalCompositeComponent domain, InstantiationContext context) {
        for (Property property : composite.getProperties().values()) {
            includeProperty(property, domain, context);
        }
        for (Include include : composite.getIncludes().values()) {
            for (Property property : include.getIncluded().getProperties().values()) {
             includeProperty(property, domain,context);
            }
        }
    }

    private void includeProperty(Property property, LogicalCompositeComponent domain, InstantiationContext context) {
        String name = property.getName();
        if (domain.getAllProperties().containsKey(name)) {
            DuplicateProperty error = new DuplicateProperty(name, domain);
            context.addError(error);
        } else {
            Document value = property.getDefaultValue();
            boolean many = property.isMany();
            QName type = property.getType();

            LogicalProperty logicalProperty = LogicalProperty.Builder.newBuilder(name, domain).xmlValue(value).many(many).type(type).build();
            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 (Resource definition : included.getResources()) {
                    LogicalResource resource = new LogicalResource<>(definition, domain);
                    domain.addResource(resource);
                }
            }
        } else {
            for (Resource definition : composite.getResources()) {
                LogicalResource resource = new LogicalResource<>(definition, domain);
                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
     */
    private void 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 (Component> definition : definitions) {
            LogicalComponent logicalComponent = instantiate(definition, domain, context);
            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);
        }

        if (channelInstantiator != null) {  // during bootstrap channel support is not available
            // 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);

            }
        }
    }

    /**
     * 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(Component definition, LogicalCompositeComponent parent, InstantiationContext context) {
        if (definition.getComponentType() instanceof Composite) {
            Component component = (Component) definition;
            return compositeComponentInstantiator.instantiate(component, parent, context);
        } else {
            Component> component = (Component>) definition;
            return atomicComponentInstantiator.instantiate(component, 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 (Component> definition : include.getIncluded().getComponents().values()) {
                LogicalComponent logicalComponent = instantiate(definition, domain, context);
                newComponents.add(logicalComponent);
                // add to the domain since includes starting from a deployable composite are "collapsed" to the domain level
                domain.addComponent(logicalComponent);
            }
        }
    }

    /**
     * Synthesizes a composite from a collection of composites using inclusion.  A counter is maintained for each include name and used to generate include
     * names in situations where they may clash, e.g. when two composites from different contributions with the same name are deployed together.
     *
     * @param composites the composites to synthesize
     * @return the synthesized composite
     */
    private Composite synthesizeComposite(List composites) {
        Composite synthesized = new Composite(SYNTHETIC_COMPOSITE);
        Map counters = new HashMap<>();
        for (Composite composite : composites) {
            Include include = new Include();
            QName name = composite.getName();
            include.setName(name);
            include.setIncluded(composite);
            if (synthesized.getIncludes().containsKey(name)) {
                AtomicInteger counter = counters.get(name);
                if (counter == null) {
                    counter = new AtomicInteger();
                    counters.put(name, counter);
                }
                include.setName(new QName(name.getNamespaceURI(), name.getLocalPart() + counter.incrementAndGet()));
            }
            synthesized.add(include);

        }
        return synthesized;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy