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

com.github.veithen.visualwas.jmx.soap.SOAPJMXConnector Maven / Gradle / Ivy

The newest version!
/*
 * #%L
 * VisualWAS
 * %%
 * Copyright (C) 2013 - 2020 Andreas Veithen
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */
package com.github.veithen.visualwas.jmx.soap;

import java.io.IOException;
import java.net.Proxy;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.management.ListenerNotFoundException;
import javax.management.MBeanServerConnection;
import javax.management.NotificationBroadcasterSupport;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.remote.JMXConnectionNotification;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.net.ssl.TrustManager;
import javax.security.auth.Subject;

import com.github.veithen.visualwas.connector.Attributes;
import com.github.veithen.visualwas.connector.Connector;
import com.github.veithen.visualwas.connector.factory.ConnectorConfiguration;
import com.github.veithen.visualwas.connector.factory.ConnectorFactory;
import com.github.veithen.visualwas.connector.feature.Feature;
import com.github.veithen.visualwas.connector.loader.ClassLoaderProvider;
import com.github.veithen.visualwas.connector.loader.SimpleClassLoaderProvider;
import com.github.veithen.visualwas.connector.notification.NotificationDispatcher;
import com.github.veithen.visualwas.connector.notification.NotificationDispatcherFeature;
import com.github.veithen.visualwas.connector.security.BasicAuthCredentials;
import com.github.veithen.visualwas.connector.security.Credentials;
import com.github.veithen.visualwas.connector.transport.Endpoint;
import com.github.veithen.visualwas.connector.transport.TransportConfiguration;

public class SOAPJMXConnector implements JMXConnector {
    private static final String ENV_PROP_PREFIX = "com.github.veithen.visualwas.jmx.soap.";
    
    // TODO: should we have a single TRANSPORT_OPTIONS attribute?
    public static final String TRUST_MANAGER = ENV_PROP_PREFIX + "trustManager";
    public static final String PROXY = ENV_PROP_PREFIX + "proxy";
    
    /**
     * Name of the attribute that specifies the connect timeout. The value must be an
     * {@link Integer} representing the timeout in milliseconds.
     */
    public static final String CONNECT_TIMEOUT = ENV_PROP_PREFIX + "connectTimeout";
    
    /**
     * Name of the attribute that specifies the class loader provider. The class loader provider
     * determines the class loader to use when deserializing values returned by WebSphere. The
     * attribute must be an instance of {@link ClassLoaderProvider}. If it is specified, then
     * {@link JMXConnectorFactory#DEFAULT_CLASS_LOADER} will be ignored. If neither
     * {@link #CLASS_LOADER_PROVIDER} nor {@link JMXConnectorFactory#DEFAULT_CLASS_LOADER} is
     * specified, then the connector will use the thread context class loader.
     */
    public static final String CLASS_LOADER_PROVIDER = ENV_PROP_PREFIX + "classLoaderProvider";
    
    /**
     * An array of {@link Feature features} to install.
     */
    public static final String FEATURES = ENV_PROP_PREFIX + "features";
    
    /**
     * Name of the attribute that specifies the exception transformer. The value must be an instance
     * of {@link ExceptionTransformer}.
     */
    public static final String EXCEPTION_TRANSFORMER = ENV_PROP_PREFIX + "exceptionTransformer";
    
    private final String host;
    private final int port;
    private final Map env;
    private final NotificationBroadcasterSupport connectionBroadcaster = new NotificationBroadcasterSupport();
    private long connectionNotificationSequence;
    private String connectionId;
    private Connector connector;
    private ExceptionTransformer exceptionTransformer;
    private boolean connected;

    public SOAPJMXConnector(String host, int port, Map env) {
        this.host = host;
        this.port = port;
        this.env = env;
    }

    @Override
    public void connect() throws IOException {
        connect(null);
    }

    public void connect(Map env) throws IOException {
        if (env == null) {
            internalConnect(this.env);
        } else {
            Map actualEnv = new HashMap<>(this.env);
            actualEnv.putAll(env);
            internalConnect(actualEnv);
        }
    }
    
    private synchronized void internalConnect(Map env) throws IOException {
        connectionId = UUID.randomUUID().toString();
        Attributes.Builder attributes = Attributes.builder();
        String[] jmxCredentials = (String[])env.get(JMXConnector.CREDENTIALS);
        if (jmxCredentials != null) {
            attributes.set(Credentials.class, new BasicAuthCredentials(jmxCredentials[0], jmxCredentials[1]));
        }
        TransportConfiguration.Builder transportConfigBuilder = TransportConfiguration.custom();
        transportConfigBuilder.setProxy((Proxy)env.get(PROXY));
        Integer connectTimeout = (Integer)env.get(CONNECT_TIMEOUT);
        if (connectTimeout != null) {
            transportConfigBuilder.setConnectTimeout(connectTimeout);
        }
        transportConfigBuilder.setTrustManager((TrustManager)env.get(TRUST_MANAGER));
        ClassLoaderProvider classLoaderProvider = (ClassLoaderProvider)env.get(CLASS_LOADER_PROVIDER);
        if (classLoaderProvider == null) {
            ClassLoader cl = (ClassLoader)env.get(JMXConnectorFactory.DEFAULT_CLASS_LOADER);
            classLoaderProvider = cl == null ? ClassLoaderProvider.TCCL : new SimpleClassLoaderProvider(cl);
        }
        ConnectorConfiguration.Builder connectorConfigBuilder = ConnectorConfiguration.custom();
        connectorConfigBuilder.setClassLoaderProvider(classLoaderProvider);
        connectorConfigBuilder.setTransportConfiguration(transportConfigBuilder.build());
        connectorConfigBuilder.addFeatures(new ConnectionIdFeature(connectionId), NotificationDispatcherFeature.INSTANCE);
        Feature[] features = (Feature[])env.get(FEATURES);
        if (features != null) {
            connectorConfigBuilder.addFeatures(features);
        }
        connector = ConnectorFactory.getInstance().createConnector(
                new Endpoint(host, port, jmxCredentials != null),
                connectorConfigBuilder.build(),
                attributes.build());
        exceptionTransformer = (ExceptionTransformer)env.get(EXCEPTION_TRANSFORMER);
        if (exceptionTransformer == null) {
            exceptionTransformer = ExceptionTransformer.DEFAULT;
        }
        try {
            // TODO: we should call isAlive here and save the session ID (so that we can detect server restarts)
            connector.getServerMBean();
        } catch (IOException ex) {
            connectionBroadcaster.sendNotification(new JMXConnectionNotification(
                    JMXConnectionNotification.FAILED,
                    this,
                    connectionId,
                    connectionNotificationSequence++,
                    "Connection failure",
                    ex));
            throw ex;
        }
        connected = true;
        connectionBroadcaster.sendNotification(new JMXConnectionNotification(
                JMXConnectionNotification.OPENED,
                this,
                connectionId,
                connectionNotificationSequence++,
                "Successfully connected",
                null));
    }

    @Override
    public synchronized MBeanServerConnection getMBeanServerConnection() throws IOException {
        return new MBeanServerConnectionImpl(connector, connector.getAdapter(NotificationDispatcher.class), exceptionTransformer);
    }

    @Override
    public synchronized MBeanServerConnection getMBeanServerConnection(Subject delegationSubject)
            throws IOException {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException();
    }

    @Override
    public synchronized void close() throws IOException {
        if (connected) {
            connector.close();
            connectionBroadcaster.sendNotification(new JMXConnectionNotification(
                    JMXConnectionNotification.CLOSED,
                    this,
                    connectionId,
                    connectionNotificationSequence++,
                    "Connection closed",
                    null));
            connected = false;
        }
    }

    @Override
    public void addConnectionNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) {
        connectionBroadcaster.addNotificationListener(listener, filter, handback);
    }

    @Override
    public void removeConnectionNotificationListener(NotificationListener listener) throws ListenerNotFoundException {
        connectionBroadcaster.removeNotificationListener(listener);
    }

    @Override
    public void removeConnectionNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException {
        connectionBroadcaster.removeNotificationListener(listener, filter, handback);
    }

    @Override
    public synchronized String getConnectionId() throws IOException {
        return connectionId;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy