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

org.fabric3.contribution.processor.JavaResourceProcessor 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.
 */
package org.fabric3.contribution.processor;

import javax.xml.namespace.QName;
import java.io.InputStream;
import java.net.URL;
import java.util.Collections;
import java.util.List;

import org.fabric3.api.host.contribution.Deployable;
import org.fabric3.api.host.runtime.HostInfo;
import org.fabric3.api.host.stream.Source;
import org.fabric3.api.model.type.component.Component;
import org.fabric3.api.model.type.component.Composite;
import org.fabric3.api.model.type.component.Include;
import org.fabric3.api.model.type.java.JavaImplementation;
import org.fabric3.spi.contribution.Constants;
import org.fabric3.spi.contribution.Contribution;
import org.fabric3.spi.contribution.ContributionManifest;
import org.fabric3.spi.contribution.JavaResourceProcessorExtension;
import org.fabric3.spi.contribution.MetaDataStore;
import org.fabric3.spi.contribution.ProcessorRegistry;
import org.fabric3.spi.contribution.Resource;
import org.fabric3.spi.contribution.ResourceElement;
import org.fabric3.spi.contribution.ResourceProcessor;
import org.fabric3.spi.contribution.ResourceState;
import org.fabric3.spi.contribution.Symbol;
import org.fabric3.spi.contribution.manifest.QNameSymbol;
import org.fabric3.spi.introspection.IntrospectionContext;
import org.fabric3.spi.introspection.java.ComponentProcessor;
import org.oasisopen.sca.annotation.EagerInit;
import org.oasisopen.sca.annotation.Reference;

/**
 * Processes a Java component resource in two phases. During contribution indexing, the Java class is introspected. At contribution processing, the component
 * resource is added to its containing composite or a new composite is created if one is not found.  Note adding the component to the composite must be done
 * after the contribution is indexed so that composites loaded from XML and model providers are in place.
 */
@EagerInit
public class JavaResourceProcessor implements ResourceProcessor {
    private ComponentProcessor componentProcessor;
    private MetaDataStore store;
    private HostInfo info;

    private List processorExtensions = Collections.emptyList();

    public JavaResourceProcessor(@Reference ProcessorRegistry registry,
                                 @Reference ComponentProcessor componentProcessor,
                                 @Reference MetaDataStore store,
                                 @Reference HostInfo info) {
        this.componentProcessor = componentProcessor;
        this.store = store;
        this.info = info;
        registry.register(this);
    }

    @Reference(required = false)
    public void setProcessorExtensions(List processorExtensions) {
        this.processorExtensions = processorExtensions;
    }

    public String getContentType() {
        return Constants.JAVA_COMPONENT_CONTENT_TYPE;
    }

    public void index(Resource resource, IntrospectionContext context) {
        // create component definition
        ResourceElement resourceElement = resource.getResourceElements().get(0);
        Class clazz = (Class) resourceElement.getValue();

        org.fabric3.api.annotation.model.Component annotation = clazz.getAnnotation(org.fabric3.api.annotation.model.Component.class);

        boolean disabled = annotation != null && !checkComponentEnabled(annotation);

        String name = clazz.getSimpleName();
        if (annotation != null && annotation.name().length() > 0) {
            name = annotation.name();
        }

        try {
            QName compositeName = getCompositeName(resourceElement, annotation);

            Component definition = new Component(name);
            definition.setContributionUri(context.getContributionUri());
            componentProcessor.process(definition, clazz, context);

            ParsedComponentSymbol symbol = new ParsedComponentSymbol(definition, disabled);
            ResourceElement parsedElement = new ResourceElement<>(symbol, compositeName);
            resource.addResourceElement(parsedElement);
        } catch (IllegalArgumentException e) {
            InvalidComponentAnnotation error = new InvalidComponentAnnotation("Invalid composite name: " + name + " on class: " + clazz.getName(), e);
            context.addError(error);
        }
    }

    private boolean checkComponentEnabled(org.fabric3.api.annotation.model.Component annotation) {
        if (annotation.environments().length > 0) {
            String hostEnvironment = info.getEnvironment();
            boolean enabled = false;
            for (String environment : annotation.environments()) {
                if (hostEnvironment.equals(environment)) {
                    enabled = true;
                    break;
                }
            }
            if (!enabled) {
                return false;
            }
        }
        return true;
    }

    private QName getCompositeName(ResourceElement resourceElement, org.fabric3.api.annotation.model.Component annotation) {
        QName compositeName;
        if (annotation != null) {
            compositeName = QName.valueOf(annotation.composite());
        } else {
            compositeName = resourceElement.getMetadata(QName.class);
            if (compositeName == null) {
                compositeName = QName.valueOf(org.fabric3.api.annotation.model.Component.DEFAULT_COMPOSITE);
            }
        }
        return compositeName;
    }

    @SuppressWarnings("unchecked")
    public void process(Resource resource, IntrospectionContext context) {
        ResourceElement resourceElement = null;
        for (ResourceElement element : resource.getResourceElements()) {
            if (element.getSymbol() instanceof ParsedComponentSymbol) {
                resourceElement = (ResourceElement) element;
                break;
            }
        }
        if (resourceElement.getSymbol().disabled) {
            // the component is disabled
            resource.setState(ResourceState.PROCESSED);
            return;
        }
        Component definition = resourceElement.getSymbol().getKey();
        QName compositeName = resourceElement.getValue();
        QNameSymbol compositeSymbol = new QNameSymbol(compositeName);
        Contribution contribution = resource.getContribution();

        Composite composite = null;
        ResourceElement element = store.resolve(context.getContributionUri(), Composite.class, compositeSymbol, context);
        if (element != null) {
            composite = element.getValue();
        }
        if (composite == null) {
            composite = new Composite(compositeName);
            composite.setContributionUri(contribution.getUri());
            composite.setDeployable(true); // make the composite deployable if it has not been defined in either a composite file or via the DSL
            NullSource source = new NullSource(compositeName.toString());
            Resource compositeResource = new Resource(contribution, source, Constants.COMPOSITE_CONTENT_TYPE);
            compositeResource.setState(ResourceState.PROCESSED);
            compositeResource.addResourceElement(new ResourceElement<>(compositeSymbol, composite));
            resource.setContribution(contribution);
            contribution.addResource(compositeResource);

            ContributionManifest manifest = contribution.getManifest();
            if (manifest.getDeployables().isEmpty()) {
                Deployable deployable = new Deployable(compositeName);
                manifest.addDeployable(deployable);
            }
            composite.add(definition);
        } else {
            composite.add(definition);
            updateIncludingComposites(contribution, composite);
        }

        for (JavaResourceProcessorExtension extension : processorExtensions) {
            extension.process(definition);
        }

        resource.setState(ResourceState.PROCESSED);
    }

    /**
     * Updates composites that include the given composite after a component has been added to the later. This is necessary since the including composite caches
     * a view of the included components.  Note only the current contribution needs to be searched as contributions are ordered on install.
     *
     * @param contribution the current contribution
     * @param composite    the composite
     */
    private void updateIncludingComposites(Contribution contribution, Composite composite) {
        for (Resource contributionResource : contribution.getResources()) {
            for (ResourceElement element : contributionResource.getResourceElements()) {
                if (element.getValue() instanceof Composite) {
                    Composite candidate = (Composite) element.getValue();
                    for (Include include : candidate.getIncludes().values()) {
                        if (include.getIncluded().getName().equals(composite.getName())) {
                            candidate.add(include);
                            break;
                        }
                    }
                }
            }
        }
    }

    private class ParsedComponentSymbol extends Symbol {
        private boolean disabled;

        public ParsedComponentSymbol(Component definition, boolean disabled) {
            super(definition);
            this.disabled = disabled;
        }
    }

    private class NullSource implements Source {
        private String name;

        private NullSource(String name) {
            this.name = name;
        }

        public String getSystemId() {
            return name;
        }

        public URL getBaseLocation() {
            return null;
        }

        public InputStream openStream() {
            return null;
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy