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

org.wildfly.discovery.DiscoveryXmlParser Maven / Gradle / Ivy

The newest version!
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2016 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * 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.wildfly.discovery;

import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;

import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;

import org.jboss.modules.Module;
import org.jboss.modules.ModuleLoadException;
import org.wildfly.client.config.ClientConfiguration;
import org.wildfly.client.config.ConfigXMLParseException;
import org.wildfly.client.config.ConfigurationXMLStreamReader;
import org.wildfly.common.Assert;
import org.wildfly.discovery.impl.AggregateDiscoveryProvider;
import org.wildfly.discovery.impl.AggregateRegistryProvider;
import org.wildfly.discovery.impl.LocalRegistryAndDiscoveryProvider;
import org.wildfly.discovery.impl.StaticDiscoveryProvider;
import org.wildfly.discovery.spi.DiscoveryProvider;
import org.wildfly.discovery.spi.ExternalDiscoveryConfigurator;
import org.wildfly.discovery.spi.RegistryProvider;

/**
 * @author David M. Lloyd
 */
final class DiscoveryXmlParser {

    private static final DiscoveryProvider[] NO_DISCOVERY_PROVIDERS = new DiscoveryProvider[0];
    private static final RegistryProvider[] NO_REGISTRY_PROVIDERS = new RegistryProvider[0];

    private DiscoveryXmlParser() {
    }

    static final String NS_DISCOVERY_1_0 = "urn:wildfly-discovery:1.0";

    static ConfiguredProvider getConfiguredProvider() {
        List discoveryProviders = new ArrayList<>();
        List registryProviders = new ArrayList<>();
        final ClientConfiguration clientConfiguration = ClientConfiguration.getInstance();
        if (clientConfiguration != null) try (final ConfigurationXMLStreamReader streamReader = clientConfiguration.readConfiguration(Collections.singleton(NS_DISCOVERY_1_0))) {
            parseConfiguration(streamReader, discoveryProviders, registryProviders);
        } catch (ConfigXMLParseException e) {
            throw new InvalidDiscoveryConfigurationException(e);
        }
        ServiceLoader loader = ServiceLoader.load(ExternalDiscoveryConfigurator.class);
        final Iterator iterator = loader.iterator();
        for (;;) try {
            if (! iterator.hasNext()) break;
            final ExternalDiscoveryConfigurator configurator = iterator.next();
            configurator.configure(
                provider -> discoveryProviders.add(Assert.checkNotNullParam("provider", provider)),
                provider -> registryProviders.add(Assert.checkNotNullParam("provider", provider))
            );
        } catch (ServiceConfigurationError | RuntimeException e) {
            // TODO log & continue
        }

        final DiscoveryProvider discoveryProvider;
        if (discoveryProviders.isEmpty()) {
            discoveryProvider = DiscoveryProvider.EMPTY;
        } else if (discoveryProviders.size() == 1) {
            discoveryProvider = discoveryProviders.get(0);
        } else {
            discoveryProvider = new AggregateDiscoveryProvider(discoveryProviders.toArray(NO_DISCOVERY_PROVIDERS));
        }
        final RegistryProvider registryProvider;
        if (registryProviders.isEmpty()) {
            registryProvider = RegistryProvider.EMPTY;
        } else if (registryProviders.size() == 1) {
            registryProvider = registryProviders.get(0);
        } else {
            registryProvider = new AggregateRegistryProvider(registryProviders.toArray(NO_REGISTRY_PROVIDERS));
        }
        return new ConfiguredProvider(discoveryProvider, registryProvider);
    }

    private static void parseConfiguration(final ConfigurationXMLStreamReader reader, final List discoveryProviders, final List registryProviders) throws ConfigXMLParseException {
        if (reader.hasNext()) {
            final int tag = reader.nextTag();
            switch (tag) {
                case START_ELEMENT: {
                    checkNamespace(reader);
                    switch (reader.getLocalName()) {
                        case "discovery": {
                            parseDiscoveryElement(reader, discoveryProviders, registryProviders);
                            return;
                        }
                        default: {
                            throw reader.unexpectedElement();
                        }
                    }
                }
                default: {
                    throw reader.unexpectedContent();
                }
            }
        }
    }

    private static void parseDiscoveryElement(final ConfigurationXMLStreamReader reader, final List discoveryProviders, final List registryProviders) throws ConfigXMLParseException {
        DiscoveryProvider discoveryProvider = DiscoveryProvider.EMPTY;
        RegistryProvider registryProvider = RegistryProvider.EMPTY;
        LocalRegistryAndDiscoveryProvider localRegistry = new LocalRegistryAndDiscoveryProvider();
        requireNoAttributes(reader);
        out: while (reader.hasNext()) {
            int tag = reader.nextTag();
            switch (tag) {
                case START_ELEMENT: {
                    checkNamespace(reader);
                    switch (reader.getLocalName()) {
                        case "discovery-provider": {
                            if (discoveryProvider != DiscoveryProvider.EMPTY) {
                                throw reader.unexpectedElement();
                            }
                            discoveryProviders.add(parseDiscoveryProvider(reader, localRegistry));
                            break;
                        }
                        case "registry-provider": {
                            if (registryProvider != RegistryProvider.EMPTY) {
                                throw reader.unexpectedElement();
                            }
                            registryProviders.add(parseRegistryProvider(reader, localRegistry));
                            break;
                        }
                        default: {
                            throw reader.unexpectedElement();
                        }
                    }
                    break;
                }
                case END_ELEMENT: {
                    break out;
                }
            }
        }
    }

    private static RegistryProvider parseRegistryProvider(final ConfigurationXMLStreamReader reader, final LocalRegistryAndDiscoveryProvider localRegistry) throws ConfigXMLParseException {
        requireNoAttributes(reader);
        RegistryProvider registryProvider;
        final int tag = reader.nextTag();
        switch (tag) {
            case START_ELEMENT: {
                checkNamespace(reader);
                switch (reader.getLocalName()) {
                    case "local-registry": {
                        registryProvider = localRegistry;
                        expectEnd(reader);
                        break;
                    }
                    case "aggregate": {
                        registryProvider = parseAggregateRegistry(reader, localRegistry);
                        break;
                    }
                    case "custom": {
                        registryProvider = parseCustom(reader, RegistryProvider.class);
                        break;
                    }
                    default: {
                        throw reader.unexpectedElement();
                    }
                }
                expectEnd(reader);
                return registryProvider;
            }
            default: {
                throw reader.unexpectedElement();
            }
        }
    }

    private static DiscoveryProvider parseDiscoveryProvider(final ConfigurationXMLStreamReader reader, final LocalRegistryAndDiscoveryProvider localRegistry) throws ConfigXMLParseException {
        requireNoAttributes(reader);
        DiscoveryProvider discoveryProvider;
        final int tag = reader.nextTag();
        switch (tag) {
            case START_ELEMENT: {
                checkNamespace(reader);
                switch (reader.getLocalName()) {
                    case "local-registry": {
                        discoveryProvider = localRegistry;
                        expectEnd(reader);
                        break;
                    }
                    case "static": {
                        discoveryProvider = parseStatic(reader);
                        break;
                    }
                    case "aggregate": {
                        discoveryProvider = parseAggregateDiscovery(reader, localRegistry);
                        break;
                    }
                    case "custom": {
                        discoveryProvider = parseCustom(reader, DiscoveryProvider.class);
                        break;
                    }
                    default: {
                        throw reader.unexpectedElement();
                    }
                }
                expectEnd(reader);
                return discoveryProvider;
            }
        }
        throw reader.missingRequiredElement(NS_DISCOVERY_1_0, "local-registry/static/aggregate/custom");
    }

    private static DiscoveryProvider parseAggregateDiscovery(final ConfigurationXMLStreamReader reader, final LocalRegistryAndDiscoveryProvider localRegistry) throws ConfigXMLParseException {
        requireNoAttributes(reader);
        final List delegates = new ArrayList<>();
        out: while (reader.hasNext()) {
            final int tag = reader.nextTag();
            switch (tag) {
                case START_ELEMENT: {
                    checkNamespace(reader);
                    switch (reader.getLocalName()) {
                        case "discovery-provider": {
                            delegates.add(parseDiscoveryProvider(reader, localRegistry));
                            break;
                        }
                        default: {
                            throw reader.unexpectedElement();
                        }
                    }
                }
                case END_ELEMENT: {
                    break out;
                }
            }
        }
        return new AggregateDiscoveryProvider(delegates.toArray(NO_DISCOVERY_PROVIDERS));
    }

    private static RegistryProvider parseAggregateRegistry(final ConfigurationXMLStreamReader reader, final LocalRegistryAndDiscoveryProvider localRegistry) throws ConfigXMLParseException {
        requireNoAttributes(reader);
        final List delegates = new ArrayList<>();
        out: while (reader.hasNext()) {
            final int tag = reader.nextTag();
            switch (tag) {
                case START_ELEMENT: {
                    checkNamespace(reader);
                    switch (reader.getLocalName()) {
                        case "registry-provider": {
                            delegates.add(parseRegistryProvider(reader, localRegistry));
                            break;
                        }
                        default: {
                            throw reader.unexpectedElement();
                        }
                    }
                }
                case END_ELEMENT: {
                    break out;
                }
            }
        }
        return new AggregateRegistryProvider(delegates.toArray(NO_REGISTRY_PROVIDERS));
    }

    private static DiscoveryProvider parseStatic(final ConfigurationXMLStreamReader reader) throws ConfigXMLParseException {
        List serviceURLs = new ArrayList<>();
        requireNoAttributes(reader);
        out: while (reader.hasNext()) {
            final int tag = reader.nextTag();
            switch (tag) {
                case START_ELEMENT: {
                    checkNamespace(reader);
                    switch (reader.getLocalName()) {
                        case "service": {
                            serviceURLs.add(parseService(reader));
                            break;
                        }
                        default: {
                            throw reader.unexpectedElement();
                        }
                    }
                    break;
                }
                case END_ELEMENT: {
                    break out;
                }
            }
        }
        return new StaticDiscoveryProvider(serviceURLs);
    }

    private static void requireNoAttributes(final ConfigurationXMLStreamReader reader) throws ConfigXMLParseException {
        if (reader.getAttributeCount() > 0) {
            throw reader.unexpectedAttribute(0);
        }
    }

    private static ServiceURL parseService(final ConfigurationXMLStreamReader reader) throws ConfigXMLParseException {
        final ServiceURL.Builder builder = new ServiceURL.Builder();
        URI uri = null;
        String uriSchemeAuthority = null;
        String abstractType = null;
        String abstractTypeAuthority = null;
        int cnt = reader.getAttributeCount();
        for (int i = 0; i < cnt; i ++) {
            checkAttributeNamespace(reader, i);
            switch (reader.getAttributeLocalName(i)) {
                case "uri": {
                    uri = reader.getURIAttributeValueResolved(i);
                    break;
                }
                case "uri-scheme-authority": {
                    uriSchemeAuthority = reader.getAttributeValueResolved(i);
                    break;
                }
                case "abstract-type": {
                    abstractType = reader.getAttributeValueResolved(i);
                    break;
                }
                case "abstract-type-authority": {
                    abstractTypeAuthority = reader.getAttributeValueResolved(i);
                    break;
                }
                default: {
                    throw reader.unexpectedAttribute(i);
                }
            }
        }
        if (uri == null) {
            throw reader.missingRequiredAttribute(null, "uri");
        }
        builder.setUri(uri);
        if (uriSchemeAuthority != null) builder.setUriSchemeAuthority(uriSchemeAuthority);
        if (abstractType != null) builder.setAbstractType(abstractType);
        if (abstractTypeAuthority != null) builder.setAbstractTypeAuthority(abstractTypeAuthority);
        out: while (reader.hasNext()) {
            final int tag = reader.nextTag();
            switch (tag) {
                case START_ELEMENT: {
                    checkNamespace(reader);
                    switch (reader.getLocalName()) {
                        case "attribute": {
                            parseAttribute(reader, builder);
                            break;
                        }
                        default: {
                            throw reader.unexpectedElement();
                        }
                    }
                    break;
                }
                case END_ELEMENT: {
                    break out;
                }
            }
        }
        return builder.create();
    }

    private static void checkAttributeNamespace(final ConfigurationXMLStreamReader reader, final int i) throws ConfigXMLParseException {
        if (reader.getAttributeNamespace(i) != null) {
            throw reader.unexpectedAttribute(i);
        }
    }

    private static void parseAttribute(final ConfigurationXMLStreamReader reader, final ServiceURL.Builder builder) throws ConfigXMLParseException {
        String name = null;
        AttributeValue value = null;
        int cnt = reader.getAttributeCount();
        for (int i = 0; i < cnt; i ++) {
            checkAttributeNamespace(reader, i);
            switch (reader.getAttributeLocalName(i)) {
                case "name": {
                    name = reader.getAttributeValueResolved(i);
                    break;
                }
                case "value": {
                    value = AttributeValue.fromString(reader.getAttributeValueResolved(i));
                    break;
                }
                default: {
                    throw reader.unexpectedAttribute(i);
                }
            }
        }
        if (name == null) {
            throw reader.missingRequiredAttribute(null, "name");
        }
        expectEnd(reader);
        if (value == null) {
            builder.addAttribute(name);
        } else {
            builder.addAttribute(name, value);
        }
    }

    private static void checkNamespace(final ConfigurationXMLStreamReader reader) throws ConfigXMLParseException {
        switch (reader.getNamespaceURI()) {
            case NS_DISCOVERY_1_0:
                break;
            default:
                throw reader.unexpectedElement();
        }
    }

    private static  T parseCustom(final ConfigurationXMLStreamReader reader, final Class type) throws ConfigXMLParseException {
        String className = null;
        String moduleName = null;
        int cnt = reader.getAttributeCount();
        for (int i = 0; i < cnt; i ++) {
            checkAttributeNamespace(reader, i);
            switch (reader.getAttributeLocalName(i)) {
                case "class": {
                    className = reader.getAttributeValueResolved(i);
                    break;
                }
                case "module": {
                    moduleName = reader.getAttributeValueResolved(i);
                    break;
                }
                default: {
                    throw reader.unexpectedAttribute(i);
                }
            }
        }
        T item;
        if (moduleName != null) {
           item = ModuleLoadDelegate.loadService(moduleName, className, type);
        } else {
            if (className != null) try {
                item = Class.forName(className, true, DiscoveryXmlParser.class.getClassLoader()).asSubclass(type).newInstance();
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
                throw new InvalidDiscoveryConfigurationException(e);
            }
            else {
                final ServiceLoader loader = ServiceLoader.load(type);
                final Iterator iterator = loader.iterator();
                try {
                    if (! iterator.hasNext()) {
                        throw new InvalidDiscoveryConfigurationException("No provider found");
                    }
                    item = iterator.next();
                } catch (ServiceConfigurationError e) {
                    throw new InvalidDiscoveryConfigurationException(e);
                }
            }
        }
        expectEnd(reader);
        return item;
    }

    static final class ModuleLoadDelegate {
        static  T loadService(String moduleName, String className, final Class type) throws ConfigXMLParseException {
            if (className != null) {
                try {
                    Module.loadClassFromCallerModuleLoader(moduleName, className).asSubclass(type).newInstance();
                } catch (ModuleLoadException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
                    throw new InvalidDiscoveryConfigurationException(e);
                }
            } else {
                try {
                    final ServiceLoader loader = Module.loadServiceFromCallerModuleLoader(moduleName, type);
                    final Iterator iterator = loader.iterator();
                    try {
                        if (!iterator.hasNext()) {
                            throw new InvalidDiscoveryConfigurationException("No provider found in module " + moduleName);
                        }
                        return iterator.next();
                    } catch (ServiceConfigurationError e) {
                        throw new InvalidDiscoveryConfigurationException(e);
                    }
                } catch (ModuleLoadException e) {
                    throw new InvalidDiscoveryConfigurationException(e);
                }
            }
            return null;
        }
    }

    private static void expectEnd(final ConfigurationXMLStreamReader reader) throws ConfigXMLParseException {
        if (reader.nextTag() != END_ELEMENT) {
            throw reader.unexpectedElement();
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy