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

org.fabric3.contribution.manifest.ContributionElementLoader 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.contribution.manifest;

import javax.xml.namespace.QName;
import javax.xml.stream.Location;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;

import org.fabric3.api.host.contribution.Deployable;
import org.fabric3.api.model.type.RuntimeMode;
import org.fabric3.spi.contribution.Capability;
import org.fabric3.spi.contribution.ContributionManifest;
import org.fabric3.spi.contribution.Export;
import org.fabric3.spi.contribution.Import;
import org.fabric3.spi.introspection.IntrospectionContext;
import org.fabric3.spi.introspection.xml.InvalidQNamePrefix;
import org.fabric3.spi.introspection.xml.InvalidValue;
import org.fabric3.spi.introspection.xml.LoaderRegistry;
import org.fabric3.spi.introspection.xml.MissingAttribute;
import org.fabric3.spi.introspection.xml.TypeLoader;
import org.fabric3.spi.introspection.xml.UnrecognizedAttribute;
import org.fabric3.spi.introspection.xml.UnrecognizedElement;
import org.fabric3.spi.model.os.Library;
import org.oasisopen.sca.annotation.Destroy;
import org.oasisopen.sca.annotation.EagerInit;
import org.oasisopen.sca.annotation.Init;
import org.oasisopen.sca.annotation.Reference;
import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
import static org.fabric3.api.Namespaces.F3;
import static org.oasisopen.sca.Constants.SCA_NS;

/**
 * Loads a contribution manifest from a contribution element
 */
@EagerInit
public class ContributionElementLoader implements TypeLoader {
    private static final QName CONTRIBUTION = new QName(SCA_NS, "contribution");
    private static final QName DEPLOYABLE = new QName(SCA_NS, "deployable");
    private static final QName SCAN = new QName(F3, "scan");
    private static final QName PROVIDES_CAPABILITY = new QName(F3, "provides.capability");
    private static final QName REQUIRES_CAPABILITY = new QName(F3, "requires.capability");

    private final LoaderRegistry registry;

    public ContributionElementLoader(@Reference LoaderRegistry registry) {
        this.registry = registry;
    }

    @Init
    public void start() {
        registry.registerLoader(CONTRIBUTION, this);
    }

    @Destroy
    public void stop() {
        registry.unregisterLoader(CONTRIBUTION);
    }

    public ContributionManifest load(XMLStreamReader reader, IntrospectionContext context) throws XMLStreamException {
        ContributionManifest manifest = new ContributionManifest();
        QName element = reader.getName();
        if (!CONTRIBUTION.equals(element)) {
            throw new AssertionError("Loader not positioned on the  element: " + element);
        }
        validateContributionAttributes(reader, context);
        boolean extension = Boolean.valueOf(reader.getAttributeValue(F3, "extension"));
        manifest.setExtension(extension);

        String bootLevelStr = reader.getAttributeValue(F3, "boot.level");

        if (bootLevelStr != null) {
            try {
                manifest.setBootLevel(Integer.parseInt(bootLevelStr));
            } catch (NumberFormatException e) {
                context.addError(new InvalidValue("Invalid boot level: " + bootLevelStr, reader.getLocation(), e));
            }
        }

        String contextPath = reader.getAttributeValue(F3, "context");
        manifest.setContext(contextPath);

        String description = reader.getAttributeValue(F3, "description");
        manifest.setDescription(description);

        while (true) {
            int event = reader.next();
            switch (event) {
                case START_ELEMENT:
                    element = reader.getName();
                    Location location = reader.getLocation();

                    if (DEPLOYABLE.equals(element)) {
                        validateDeployableAttributes(reader, context);
                        String name = reader.getAttributeValue(null, "composite");
                        if (name == null) {
                            MissingManifestAttribute failure = new MissingManifestAttribute("Composite attribute must be specified", location);
                            context.addError(failure);
                            return null;
                        }
                        QName qName;
                        // read qname but only set namespace if it is explicitly declared
                        int index = name.indexOf(':');
                        if (index != -1) {
                            String prefix = name.substring(0, index);
                            String localPart = name.substring(index + 1);
                            String ns = reader.getNamespaceContext().getNamespaceURI(prefix);
                            if (ns == null) {
                                URI uri = context.getContributionUri();
                                context.addError(new InvalidQNamePrefix(
                                        "The prefix " + prefix + " specified in the contribution manifest file for " + uri + " is invalid", location));
                                return null;
                            }
                            qName = new QName(ns, localPart, prefix);
                        } else {
                            qName = new QName(null, name);
                        }
                        List runtimeModes = parseRuntimeModes(reader, context);
                        List environments = parseEnvironments(reader);
                        Deployable deployable = new Deployable(qName, runtimeModes, environments);
                        manifest.addDeployable(deployable);
                    } else if (REQUIRES_CAPABILITY.equals(element)) {
                        parseRequiredCapabilities(manifest, reader, context);
                    } else if (PROVIDES_CAPABILITY.equals(element)) {
                        parseProvidedCapabilities(manifest, reader, context);
                    } else if (SCAN.equals(element)) {
                        validateScanAttributes(reader, context);
                        String excludeAttr = reader.getAttributeValue(null, "exclude");
                        if (excludeAttr == null) {
                            MissingAttribute error = new MissingAttribute("The exclude attribute must be set on the scan element", location);
                            context.addError(error);
                            continue;
                        }
                        String[] excludes = excludeAttr.split(",");
                        List patterns = new ArrayList<>();
                        for (String exclude : excludes) {
                            patterns.add(Pattern.compile(exclude));
                        }
                        manifest.setScanExcludes(patterns);

                    } else {
                        Object object = registry.load(reader, Object.class, context);
                        if (object instanceof Export) {
                            manifest.addExport((Export) object);
                        } else if (object instanceof Import) {
                            manifest.addImport((Import) object);
                        } else if (object instanceof ExtendsDeclaration) {
                            ExtendsDeclaration declaration = (ExtendsDeclaration) object;
                            manifest.addExtend(declaration.getName());
                        } else if (object instanceof ProvidesDeclaration) {
                            ProvidesDeclaration declaration = (ProvidesDeclaration) object;
                            manifest.addExtensionPoint(declaration.getName());
                        } else if (object instanceof Library) {
                            Library library = (Library) object;
                            manifest.addLibrary(library);
                        } else if (object != null) {
                            UnrecognizedElement failure = new UnrecognizedElement(reader, location);
                            context.addError(failure);
                            return null;
                        }
                    }
                    break;
                case XMLStreamConstants.END_ELEMENT:
                    if (CONTRIBUTION.equals(reader.getName())) {
                        return manifest;
                    }
                    break;
            }
        }
    }

    private void parseProvidedCapabilities(ContributionManifest manifest, XMLStreamReader reader, IntrospectionContext context) {
        Location location = reader.getLocation();
        String name = reader.getAttributeValue(null, "name");
        if (name == null) {
            MissingAttribute error = new MissingAttribute("Capability name must be specified", location);
            context.addError(error);
            return;
        }
        Capability capability = new Capability(name);
        manifest.addProvidedCapability(capability);
    }

    private void parseRequiredCapabilities(ContributionManifest manifest, XMLStreamReader reader, IntrospectionContext context) {
        Location location = reader.getLocation();
        String name = reader.getAttributeValue(null, "name");
        if (name == null) {
            MissingAttribute error = new MissingAttribute("Capability name must be specified", location);
            context.addError(error);
            return;
        }
        boolean loaded = Boolean.valueOf(reader.getAttributeValue(null, "loaded"));
        Capability capability = new Capability(name, loaded);
        manifest.addRequiredCapability(capability);
    }

    private List parseRuntimeModes(XMLStreamReader reader, IntrospectionContext context) {
        String modeAttr = reader.getAttributeValue(null, "modes");
        List runtimeModes;
        if (modeAttr == null) {
            runtimeModes = Deployable.DEFAULT_MODES;
        } else {
            String[] modes = modeAttr.trim().split(" ");
            runtimeModes = new ArrayList<>();
            for (String mode : modes) {
                if ("vm".equals(mode)) {
                    runtimeModes.add(RuntimeMode.VM);
                } else if ("node".equals(mode)) {
                    runtimeModes.add(RuntimeMode.NODE);
                } else {
                    runtimeModes = Deployable.DEFAULT_MODES;
                    Location location = reader.getLocation();
                    InvalidValue error = new InvalidValue("Invalid mode attribute: " + modeAttr, location);
                    context.addError(error);
                    break;
                }
            }
        }
        return runtimeModes;
    }

    private List parseEnvironments(XMLStreamReader reader) {
        String modeAttr = reader.getAttributeValue(null, "environments");
        if (modeAttr == null) {
            return Collections.emptyList();
        } else {
            return Arrays.asList(modeAttr.trim().split(" "));
        }
    }

    private void validateContributionAttributes(XMLStreamReader reader, IntrospectionContext context) {
        Location location = reader.getLocation();
        for (int i = 0; i < reader.getAttributeCount(); i++) {
            String name = reader.getAttributeLocalName(i);
            if (!"extension".equals(name) && !"description".equals(name) && !"context".equals(name) && !"capabilities".equals(name)
                && !"required-capabilities".equals(name) && !"boot.level".equals(name)) {
                context.addError(new UnrecognizedAttribute(name, location));
            }
        }
    }

    private void validateDeployableAttributes(XMLStreamReader reader, IntrospectionContext context) {
        Location location = reader.getLocation();
        for (int i = 0; i < reader.getAttributeCount(); i++) {
            String name = reader.getAttributeLocalName(i);
            if (!"composite".equals(name) && !"modes".equals(name) && !"environments".equals(name)) {
                context.addError(new UnrecognizedAttribute(name, location));
            }
        }
    }

    private void validateScanAttributes(XMLStreamReader reader, IntrospectionContext context) {
        Location location = reader.getLocation();
        for (int i = 0; i < reader.getAttributeCount(); i++) {
            String name = reader.getAttributeLocalName(i);
            if (!"exclude".equals(name)) {
                context.addError(new UnrecognizedAttribute(name, location));
            }
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy