org.jboss.tools.jmx.jolokia.JolokiaConnectionWrapper.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.tools.jmx.jolokia.JolokiaConnectionWrapper.java

Source

/*******************************************************************************
 * Copyright (c) 2013 Red Hat, Inc.
 * Distributed under license by Red Hat, Inc. All rights reserved.
 * This program is made available under the terms of the
 * Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Red Hat, Inc. - initial API and implementation
 ******************************************************************************/

package org.jboss.tools.jmx.jolokia;

import java.io.IOException;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.Header;
import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.Args;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
import org.jboss.tools.jmx.core.AbstractConnectionProvider;
import org.jboss.tools.jmx.core.ExtensionManager;
import org.jboss.tools.jmx.core.IConnectionProvider;
import org.jboss.tools.jmx.core.IConnectionWrapper;
import org.jboss.tools.jmx.core.IJMXRunnable;
import org.jboss.tools.jmx.core.JMXActivator;
import org.jboss.tools.jmx.core.JMXCoreMessages;
import org.jboss.tools.jmx.core.JMXException;
import org.jboss.tools.jmx.core.tree.NodeUtils;
import org.jboss.tools.jmx.core.tree.Root;
import org.jboss.tools.jmx.jolokia.internal.Activator;
import org.jboss.tools.jmx.jolokia.internal.JolokiaConnectionProvider;
import org.jboss.tools.jmx.jolokia.internal.connection.JolokiaMBeanServerConnection;
import org.jboss.tools.jmx.jolokia.internal.model.builder.CustomClientBuilder;
import org.jolokia.client.J4pClient;
import org.jolokia.client.exception.J4pException;
import org.jolokia.client.request.J4pReadRequest;
import org.jolokia.client.request.J4pReadResponse;

/**
 * A class representing a Jolokia jmx connection as per the jmx.core API. 
 * It stores key information, like an id, headers, get or post type, and url. 
 * It will also run arbitrary jmx runnables. 
 * 
 */
public class JolokiaConnectionWrapper implements IConnectionWrapper, IAdaptable {

    public static final String ID = "id";
    public static final String URL = "url";
    public static final String HEADERS = "headers";
    public static final String IGNORE_SSL_ERRORS = "ignoreSSLErrors";
    public static final String GET_OR_POST = "getOrPost";

    private String id;
    private String url;
    private Map<String, String> headers;
    private boolean ignoreSSLErrors = false;

    private Root root;
    private boolean connected;
    private String type = "POST"; // GET or POST

    private JolokiaMBeanServerConnection connection = null;

    public JolokiaConnectionWrapper() {
    }

    @Override
    public String toString() {
        return getName();
    }

    public MBeanServerConnection getConnection() {
        if (connection == null) {
            J4pClient j4pClient = createJ4pClient();
            connection = new JolokiaMBeanServerConnection(j4pClient, type);
        }
        return connection;
    }

    public synchronized void connect() throws IOException {
        verifyServerReachable();
        fireConnectionChanged();
    }

    public synchronized void disconnect() throws IOException {
        root = null;
        setConnected(false);
        fireConnectionChanged();
    }

    public boolean isConnected() {
        return connected;
    }

    public Root getRoot() {
        return root;
    }

    public void loadRoot() {
        loadRoot(new NullProgressMonitor());
    }

    @Override
    public void loadRoot(IProgressMonitor monitor) {
        if (monitor == null)
            monitor = new NullProgressMonitor();
        if (isConnected() && root == null) {
            try {
                root = NodeUtils.createObjectNameTree(this, monitor);
            } catch (Throwable e) {
                Activator.pluginLog().logWarning("Failed to load JMX tree for " + this + ". " + e, e);
            }
        }
    }

    protected J4pClient createJ4pClient() {
        CustomClientBuilder jb = new CustomClientBuilder() {
            @Override
            public void clientBuilderAdditions(HttpClientBuilder builder) {
                Set<Header> defaultHeaders = headers.entrySet().stream()
                        .map(entry -> new BasicHeader(entry.getKey(), entry.getValue()))
                        .collect(Collectors.toSet());
                builder.setDefaultHeaders(defaultHeaders);
            }

            @Override
            protected SSLConnectionSocketFactory createDefaultSSLConnectionSocketFactory() {
                if (ignoreSSLErrors) {
                    try {
                        final SSLContext sslcontext = SSLContext.getInstance("TLS");
                        sslcontext.init(null, new TrustManager[] { new AcceptAllTrustManager() }, null);
                        return new JolokiaSSLConnectionSocketFactory(sslcontext, new NoopHostnameVerifier());
                    } catch (NoSuchAlgorithmException e1) {
                        Activator.pluginLog().logWarning(e1);
                    } catch (KeyManagementException e) {
                        Activator.pluginLog().logWarning(e);
                    }
                }
                SSLContext sslcontext = SSLContexts.createSystemDefault();
                X509HostnameVerifier hostnameVerifier = new BrowserCompatHostnameVerifier();
                return new SSLConnectionSocketFactory(sslcontext, hostnameVerifier);
            }
        };
        jb.url(url);
        return jb.build();
    }

    private static class AcceptAllTrustManager implements X509TrustManager {

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            // TODO Auto-generated method stub
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            // TODO Auto-generated method stub
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            // TODO Auto-generated method stub
            return null;
        }

    }

    private static class JolokiaSSLConnectionSocketFactory extends SSLConnectionSocketFactory {
        private javax.net.ssl.SSLSocketFactory sockFact;

        public JolokiaSSLConnectionSocketFactory(final SSLContext sslContext) {
            this(sslContext, getDefaultHostnameVerifier());
        }

        /**
         * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(javax.net.ssl.SSLContext,
         *   javax.net.ssl.HostnameVerifier)}
         */
        @Deprecated
        public JolokiaSSLConnectionSocketFactory(final SSLContext sslContext,
                final X509HostnameVerifier hostnameVerifier) {
            this(Args.notNull(sslContext, "SSL context").getSocketFactory(), null, null, hostnameVerifier);
        }

        /**
         * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(javax.net.ssl.SSLContext,
         *   String[], String[], javax.net.ssl.HostnameVerifier)}
         */
        @Deprecated
        public JolokiaSSLConnectionSocketFactory(final SSLContext sslContext, final String[] supportedProtocols,
                final String[] supportedCipherSuites, final X509HostnameVerifier hostnameVerifier) {
            this(Args.notNull(sslContext, "SSL context").getSocketFactory(), supportedProtocols,
                    supportedCipherSuites, hostnameVerifier);
        }

        /**
         * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(javax.net.ssl.SSLSocketFactory,
         *   javax.net.ssl.HostnameVerifier)}
         */
        @Deprecated
        public JolokiaSSLConnectionSocketFactory(final javax.net.ssl.SSLSocketFactory socketfactory,
                final X509HostnameVerifier hostnameVerifier) {
            this(socketfactory, null, null, hostnameVerifier);
        }

        /**
         * @deprecated (4.4) Use {@link #SSLConnectionSocketFactory(javax.net.ssl.SSLSocketFactory,
         *   String[], String[], javax.net.ssl.HostnameVerifier)}
         */
        @Deprecated
        public JolokiaSSLConnectionSocketFactory(final javax.net.ssl.SSLSocketFactory socketfactory,
                final String[] supportedProtocols, final String[] supportedCipherSuites,
                final X509HostnameVerifier hostnameVerifier) {
            this(socketfactory, supportedProtocols, supportedCipherSuites, (HostnameVerifier) hostnameVerifier);
        }

        /**
         * @since 4.4
         */
        public JolokiaSSLConnectionSocketFactory(final SSLContext sslContext,
                final HostnameVerifier hostnameVerifier) {
            this(Args.notNull(sslContext, "SSL context").getSocketFactory(), null, null, hostnameVerifier);
        }

        /**
         * @since 4.4
         */
        public JolokiaSSLConnectionSocketFactory(final SSLContext sslContext, final String[] supportedProtocols,
                final String[] supportedCipherSuites, final HostnameVerifier hostnameVerifier) {
            this(Args.notNull(sslContext, "SSL context").getSocketFactory(), supportedProtocols,
                    supportedCipherSuites, hostnameVerifier);
        }

        /**
         * @since 4.4
         */
        public JolokiaSSLConnectionSocketFactory(final javax.net.ssl.SSLSocketFactory socketfactory,
                final HostnameVerifier hostnameVerifier) {
            this(socketfactory, null, null, hostnameVerifier);
        }

        /**
         * @since 4.4
         */
        public JolokiaSSLConnectionSocketFactory(final javax.net.ssl.SSLSocketFactory socketfactory,
                final String[] supportedProtocols, final String[] supportedCipherSuites,
                final HostnameVerifier hostnameVerifier) {
            super(socketfactory, supportedProtocols, supportedCipherSuites, hostnameVerifier);
            sockFact = socketfactory;
        }

        @Override
        public Socket createSocket(final HttpContext context) throws IOException {
            return sockFact.createSocket();
        }

    }

    protected void verifyServerReachable() throws IOException {
        J4pClient j4pClient = createJ4pClient();
        try {
            J4pReadRequest req = new J4pReadRequest("java.lang:type=Memory", "HeapMemoryUsage");
            J4pReadResponse resp = j4pClient.execute(req);
            Map<String, String> vals = resp.getValue();
            Object used = vals.get("used");
            Object max = vals.get("max");

            int used2 = (used instanceof Number ? ((Number) used).intValue() : -1);
            int max2 = (max instanceof Number ? ((Number) used).intValue() : -1);
            int usage = (int) (used2 * 100 / max2);
            //System.out.println("Memory usage: used: " + used2 + " / max: " + max2 + " = " + usage + "%");
            setConnected(true);
        } catch (MalformedObjectNameException mone) {
            throw new IOException(mone);
        } catch (J4pException e) {
            throw new IOException(e);
        }
    }

    protected void setConnected(boolean b) {
        connected = b;
    }

    @Override
    public void run(IJMXRunnable runnable) throws JMXException {
        try {
            runnable.run(getConnection());
        } catch (Exception ce) {
            IStatus s = new Status(IStatus.ERROR, JMXActivator.PLUGIN_ID,
                    JMXCoreMessages.DefaultConnection_ErrorRunningJMXCode, ce);
            throw new JMXException(s);
        }
    }

    @Override
    public void run(IJMXRunnable runnable, HashMap<String, String> prefs) throws JMXException {
        run(runnable);
    }

    @Override
    public boolean canControl() {
        return true;
    }

    protected void fireConnectionChanged() {
        AbstractConnectionProvider provider = (AbstractConnectionProvider) getProvider();
        provider.fireChanged(this);
    }

    @Override
    public IConnectionProvider getProvider() {
        return ExtensionManager.getProvider(JolokiaConnectionProvider.PROVIDER_ID);
    }

    @Override
    public int hashCode() {
        return super.hashCode(); // TODO
    }

    @Override
    public boolean equals(Object obj) {
        return obj instanceof JolokiaConnectionWrapper; // TODO And other stuff
    }

    // UI Integration with properties page
    public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) {
        ITabbedPropertySheetPageContributor contributor = new ITabbedPropertySheetPageContributor() {
            @Override
            public String getContributorId() {
                return "org.jboss.tools.jmx.jvmmonitor.ui.JvmExplorer";
            }
        };
        if (adapter == IPropertySheetPage.class) {
            return new TabbedPropertySheetPage(contributor);
        } else if (adapter == ITabbedPropertySheetPageContributor.class) {
            return contributor;
        }
        return null;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return id;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
        connection = null;
    }

    public Map<String, String> getHeaders() {
        return headers;
    }

    public void setHeaders(Map<String, String> headers) {
        this.headers = headers;
        connection = null;
    }

    public boolean isIgnoreSSLErrors() {
        return ignoreSSLErrors;
    }

    public void setIgnoreSSLErrors(boolean ignoreSSLErrors) {
        this.ignoreSSLErrors = ignoreSSLErrors;
        connection = null;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
        connection = null;
    }
}