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

org.jboss.ejb.client.ConfigurationBasedEJBClientContextSelector Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 34.0.0.Final
Show newest version
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2017 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.jboss.ejb.client;

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

import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
import java.util.Set;

import org.jboss.ejb._private.Logs;
import org.jboss.ejb.client.legacy.LegacyPropertiesConfiguration;
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;

/**
 * A one-time, configuration-based Enterprise Bean client context configurator.
 *
 * @author David M. Lloyd
 * @author Joerg Baesner
 */
final class ConfigurationBasedEJBClientContextSelector {
    private static final EJBClientContext configuredContext;

    private static final String NS_EJB_CLIENT_3_0 = "urn:jboss:wildfly-client-ejb:3.0";
    private static final String NS_EJB_CLIENT_3_1 = "urn:jboss:wildfly-client-ejb:3.1";
    private static final String NS_EJB_CLIENT_3_2 = "urn:jboss:wildfly-client-ejb:3.2";
    private static final String NS_INCORRECT = "urn:jboss:ejb-client:3.0";

    private static final Set validNamespaces = new HashSet<>(Arrays.asList(NS_EJB_CLIENT_3_0, NS_EJB_CLIENT_3_1,
            NS_EJB_CLIENT_3_2));

    static {
        configuredContext = loadConfiguration();
    }

    private ConfigurationBasedEJBClientContextSelector() {
    }

    private static EJBClientContext loadConfiguration() {
        final ClientConfiguration clientConfiguration = ClientConfiguration.getInstance();
        final ClassLoader classLoader = ConfigurationBasedEJBClientContextSelector.class.getClassLoader();
        final EJBClientContext.Builder builder = new EJBClientContext.Builder();
        loadTransportProviders(builder, classLoader);
        if (clientConfiguration != null) try {
            try (final ConfigurationXMLStreamReader streamReader = clientConfiguration.readConfiguration(validNamespaces)) {
                parseEJBClientConfiguration(streamReader, builder);
            }
        } catch (ConfigXMLParseException e) {
            throw new IllegalStateException(e);
        }
        LegacyPropertiesConfiguration.configure(builder);
        return builder.build();
    }

    private static void parseEJBClientConfiguration(final ConfigurationXMLStreamReader streamReader, final EJBClientContext.Builder builder) throws ConfigXMLParseException {
        if (streamReader.hasNext()) {
            if (streamReader.nextTag() == START_ELEMENT) {
                String namespaceURI = streamReader.getNamespaceURI();
                // TODO: temporary
                if (namespaceURI.equals(NS_INCORRECT)) {
                    throw new ConfigXMLParseException("The namespace \"" + NS_INCORRECT + "\" was incorrect; replace with \"" + NS_EJB_CLIENT_3_1 + "\"", streamReader);
                }
                if (! validNamespaces.contains(namespaceURI) || ! streamReader.getLocalName().equals("jboss-ejb-client")) {
                    throw streamReader.unexpectedElement();
                }
                parseEJBClientType(streamReader, builder);
                return;
            }
            throw streamReader.unexpectedContent();
        }
    }

    private static void parseEJBClientType(final ConfigurationXMLStreamReader streamReader, final EJBClientContext.Builder builder) throws ConfigXMLParseException {
        if (streamReader.getAttributeCount() > 0) {
            throw streamReader.unexpectedAttribute(0);
        }
        boolean gotInvocationTimeout = false;
        boolean gotGlobalInterceptors = false;
        boolean gotConnections = false;
        boolean gotClusterNodeSelector = false;
        boolean gotDeploymentNodeSelector = false;
        boolean gotMaximumConnectedClusterNodes = false;
        for (;;) {
            final int next = streamReader.nextTag();
            if (next == START_ELEMENT) {
                String configuredNamespace = streamReader.getNamespaceURI();
                if (! validNamespaces.contains(configuredNamespace)) {
                    throw streamReader.unexpectedElement();
                }
                final String localName = streamReader.getLocalName();
                if (localName.equals("invocation-timeout") && ! gotInvocationTimeout && inValidNamespace(validNamespaces, configuredNamespace)) {
                    gotInvocationTimeout = true;
                    parseInvocationTimeoutType(streamReader, builder);
                }
                else if (localName.equals("global-interceptors") && ! gotGlobalInterceptors && inValidNamespace(validNamespaces, configuredNamespace)) {
                    gotGlobalInterceptors = true;
                    parseInterceptorsType(streamReader, builder);
                } 
                else if (localName.equals("connections") && ! gotConnections && inValidNamespace(validNamespaces, configuredNamespace)) {
                    gotConnections = true;
                    parseConnectionsType(streamReader, builder);
                }
                else  if(localName.equals("deployment-node-selector") && ! gotDeploymentNodeSelector
                        && inValidNamespace(new HashSet<>(Arrays.asList(NS_EJB_CLIENT_3_1, NS_EJB_CLIENT_3_2)),
                        configuredNamespace)) {
                    gotDeploymentNodeSelector = true;
                    parseDeploymentNodeSelectorType(streamReader, builder);
                }
                else  if(localName.equals("cluster-node-selector") && ! gotClusterNodeSelector
                        && inValidNamespace(new HashSet<>(Arrays.asList(NS_EJB_CLIENT_3_1, NS_EJB_CLIENT_3_2)), configuredNamespace)) {
                    gotClusterNodeSelector = true;
                    parseClusterNodeSelectorType(streamReader, builder);
                }
                else if (localName.equals("max-allowed-connected-nodes") && ! gotMaximumConnectedClusterNodes
                        && inValidNamespace(Collections.singleton(NS_EJB_CLIENT_3_2), configuredNamespace)) {
                    gotMaximumConnectedClusterNodes = true;
                    parseMaximumAllowedClusterNodesType(streamReader, builder);
                }
                else {
                    throw streamReader.unexpectedElement();
                }
            } else if (next == END_ELEMENT) {
                return;
            } else {
                throw Assert.unreachableCode();
            }
        }
    }

    private static boolean inValidNamespace(Set validNamespaces, String configuredNamespace) {
        return validNamespaces.contains(configuredNamespace);
    }
    
    private static void parseInvocationTimeoutType(final ConfigurationXMLStreamReader streamReader, final EJBClientContext.Builder builder) throws ConfigXMLParseException {
        final int attributeCount = streamReader.getAttributeCount();
        int timeout = -1 ;
        for (int i = 0; i < attributeCount; i++) {
            if (streamReader.getAttributeNamespace(i) != null && ! streamReader.getAttributeNamespace(i).isEmpty()) {
                throw streamReader.unexpectedAttribute(i);
            }
            final String name = streamReader.getAttributeLocalName(i);
            if (name.equals("seconds")) {
                timeout = streamReader.getIntAttributeValueResolved(i);
            } else {
                throw streamReader.unexpectedAttribute(i);
            }
            // convert timeout in seconds to ms
            long timeoutInMs = timeout == -1 ? timeout : timeout * 1000;
            builder.setInvocationTimeout(timeoutInMs);
        }
        final int next = streamReader.nextTag();
        if (next == END_ELEMENT) {
            return;
        }
        throw streamReader.unexpectedElement();
    }

    private static void parseInterceptorsType(final ConfigurationXMLStreamReader streamReader, final EJBClientContext.Builder builder) throws ConfigXMLParseException {
        if (streamReader.getAttributeCount() > 0) {
            throw streamReader.unexpectedAttribute(0);
        }
        for (;;) {
            final int next = streamReader.nextTag();
            if (next == START_ELEMENT) {
                if (! validNamespaces.contains(streamReader.getNamespaceURI()) || ! streamReader.getLocalName().equals("interceptor")) {
                    throw streamReader.unexpectedElement();
                }
                parseInterceptorType(streamReader, builder);
            } else if (next == END_ELEMENT) {
                return;
            } else {
                throw Assert.unreachableCode();
            }
        }
    }

    private static void parseInterceptorType(final ConfigurationXMLStreamReader streamReader, final EJBClientContext.Builder builder) throws ConfigXMLParseException {
        final Class interceptorClass = parseClassType(streamReader, EJBClientInterceptor.class);
        builder.addInterceptor(interceptorClass);
    }

    private static void parseClusterNodeSelectorType(final ConfigurationXMLStreamReader streamReader, final EJBClientContext.Builder builder) throws ConfigXMLParseException {
        final Class clusterNodeSelectorClass = parseClassType(streamReader, ClusterNodeSelector.class);
        try {
            builder.setClusterNodeSelector(clusterNodeSelectorClass.newInstance());
        } catch (InstantiationException | IllegalAccessException e) {
            throw new ConfigXMLParseException(e);
        }
    }

    private static void parseDeploymentNodeSelectorType(final ConfigurationXMLStreamReader streamReader, final EJBClientContext.Builder builder) throws ConfigXMLParseException {
        final Class deploymentNodeSelectorClass = parseClassType(streamReader, DeploymentNodeSelector.class);
        try {
            builder.setDeploymentNodeSelector(deploymentNodeSelectorClass.newInstance());
        } catch (InstantiationException | IllegalAccessException e) {
            throw new ConfigXMLParseException(e);
        }
    }

    private static  Class parseClassType(final ConfigurationXMLStreamReader streamReader, Class interfaceToImplement) throws ConfigXMLParseException {
        final int attributeCount = streamReader.getAttributeCount();
        String className = null;
        String moduleName = null;
        for (int i = 0; i < attributeCount; i++) {
            if (streamReader.getAttributeNamespace(i) != null && ! streamReader.getAttributeNamespace(i).isEmpty()) {
                throw streamReader.unexpectedAttribute(i);
            }
            final String name = streamReader.getAttributeLocalName(i);
            if (name.equals("class")) {
                className = streamReader.getAttributeValueResolved(i);
            } else if (name.equals("moduleName")) {
                moduleName = streamReader.getAttributeValueResolved(i);
            } else {
                throw streamReader.unexpectedAttribute(i);
            }
        }
        if (className == null) {
            throw streamReader.missingRequiredAttribute(null, "class");
        }
        ClassLoader cl;
        if (moduleName != null) {
            try {
                cl = ModuleLoadDelegate.loadModule(moduleName);
            } catch (LinkageError e) {
                throw Logs.MAIN.noJBossModules(streamReader);
            }
        } else {
            cl = ConfigurationBasedEJBClientContextSelector.class.getClassLoader();
        }
        final Class clazz;
        try {
            clazz = Class.forName(className, false, cl).asSubclass(interfaceToImplement);
            
        } catch (ClassNotFoundException | ClassCastException e) {
            throw new ConfigXMLParseException(e);
        }

        final int next = streamReader.nextTag();
        if (next == END_ELEMENT) {
            return clazz;
        }
        throw streamReader.unexpectedElement();
    }

    static final class ModuleLoadDelegate {
        static ClassLoader loadModule(String moduleName) throws ConfigXMLParseException {
            try {
                return Module.getModuleFromCallerModuleLoader(moduleName).getClassLoader();
            } catch (ModuleLoadException e) {
                throw new ConfigXMLParseException(e);
            }
        }
    }

    private static void parseConnectionsType(final ConfigurationXMLStreamReader streamReader, final EJBClientContext.Builder builder) throws ConfigXMLParseException {
        if (streamReader.getAttributeCount() > 0) {
            throw streamReader.unexpectedAttribute(0);
        }
        for (;;) {
            final int next = streamReader.nextTag();
            if (next == START_ELEMENT) {
                if (! validNamespaces.contains(streamReader.getNamespaceURI())) {
                    throw streamReader.unexpectedElement();
                }
                final String localName = streamReader.getLocalName();
                if (localName.equals("connection")) {
                    parseConnectionType(streamReader, builder);
                } else {
                    throw streamReader.unexpectedElement();
                }
            } else if (next == END_ELEMENT) {
                return;
            } else {
                throw Assert.unreachableCode();
            }
        }
    }

    private static void parseConnectionType(final ConfigurationXMLStreamReader streamReader, final EJBClientContext.Builder builder) throws ConfigXMLParseException {
        URI uri = null;
        final int attributeCount = streamReader.getAttributeCount();
        for (int i = 0; i < attributeCount; i ++) {
            if (streamReader.getAttributeNamespace(i) != null && ! streamReader.getAttributeNamespace(i).isEmpty() || ! streamReader.getAttributeLocalName(i).equals("uri") || uri != null) {
                throw streamReader.unexpectedAttribute(i);
            }
            uri = streamReader.getURIAttributeValueResolved(i);
        }
        if (uri == null) {
            throw streamReader.missingRequiredAttribute(null, "uri");
        }
        final int next = streamReader.nextTag();
        if (next == START_ELEMENT) {
            if (! validNamespaces.contains(streamReader.getNamespaceURI())) {
                throw streamReader.unexpectedElement();
            }
            final String localName = streamReader.getLocalName();
            if (localName.equals("interceptors")) {
                // todo...
                streamReader.skipContent();
            }
        } else if (next == END_ELEMENT) {
            final EJBClientConnection.Builder connBuilder = new EJBClientConnection.Builder();
            connBuilder.setDestination(uri);
            builder.addClientConnection(connBuilder.build());
            return;
        } else {
            throw Assert.unreachableCode();
        }
    }
    private static void parseMaximumAllowedClusterNodesType(final ConfigurationXMLStreamReader streamReader, final EJBClientContext.Builder builder) throws ConfigXMLParseException {
        final int attributeCount = streamReader.getAttributeCount();
        int maximumConnectedClusterNodes;
        for (int i = 0; i < attributeCount; i++) {
            if (streamReader.getAttributeNamespace(i) != null && ! streamReader.getAttributeNamespace(i).isEmpty()) {
                throw streamReader.unexpectedAttribute(i);
            }
            final String name = streamReader.getAttributeLocalName(i);
            if (name.equals("nodes")) {
                maximumConnectedClusterNodes = streamReader.getIntAttributeValueResolved(i);
            } else {
                throw streamReader.unexpectedAttribute(i);
            }
            builder.setMaximumConnectedClusterNodes(maximumConnectedClusterNodes);
        }
        final int next = streamReader.nextTag();
        if (next == END_ELEMENT) {
            return;
        }
        throw streamReader.unexpectedElement();
    }

    private static void loadTransportProviders(final EJBClientContext.Builder builder, final ClassLoader classLoader) {
        final ServiceLoader serviceLoader = ServiceLoader.load(EJBTransportProvider.class, classLoader);
        Iterator iterator = serviceLoader.iterator();
        for (;;) try {
            if (! iterator.hasNext()) break;
            final EJBTransportProvider transportProvider = iterator.next();
            builder.addTransportProvider(transportProvider);
        } catch (ServiceConfigurationError ignored) {
            Logs.MAIN.error("Failed to load service", ignored);
        }
    }

    static EJBClientContext get() {
        return configuredContext;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy