org.wso2.carbon.analytics.jmx.agent.tasks.JmxTask.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.analytics.jmx.agent.tasks.JmxTask.java

Source

/*
*  Copyright (c) WSO2 Inc. (http://wso2.com) All Rights Reserved.
    
  WSO2 Inc. licenses this file to you 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.wso2.carbon.analytics.jmx.agent.tasks;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.analytics.jmx.agent.JmxAgent;
import org.wso2.carbon.analytics.jmx.agent.JmxConstant;
import org.wso2.carbon.analytics.jmx.agent.PublisherUtil;
import org.wso2.carbon.analytics.jmx.agent.TenantPublisherConfigData;
import org.wso2.carbon.analytics.jmx.agent.exceptions.JmxConnectionException;
import org.wso2.carbon.analytics.jmx.agent.exceptions.JmxMBeanException;
import org.wso2.carbon.analytics.jmx.agent.exceptions.JmxProfileException;
import org.wso2.carbon.analytics.jmx.agent.exceptions.ProfileDoesNotExistException;
import org.wso2.carbon.analytics.jmx.agent.profiles.MBean;
import org.wso2.carbon.analytics.jmx.agent.profiles.MBeanAttribute;
import org.wso2.carbon.analytics.jmx.agent.profiles.MBeanAttributeProperty;
import org.wso2.carbon.analytics.jmx.agent.profiles.Profile;
import org.wso2.carbon.analytics.jmx.agent.profiles.ProfileManager;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.databridge.agent.thrift.DataPublisher;
import org.wso2.carbon.databridge.agent.thrift.exception.AgentException;
import org.wso2.carbon.databridge.commons.Event;
import org.wso2.carbon.databridge.commons.exception.AuthenticationException;
import org.wso2.carbon.databridge.commons.exception.DifferentStreamDefinitionAlreadyDefinedException;
import org.wso2.carbon.databridge.commons.exception.MalformedStreamDefinitionException;
import org.wso2.carbon.databridge.commons.exception.StreamDefinitionException;
import org.wso2.carbon.databridge.commons.exception.TransportException;
import org.wso2.carbon.ntask.core.AbstractTask;

import javax.management.openmbean.CompositeData;
import javax.management.remote.JMXConnector;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Map;

public class JmxTask extends AbstractTask {

    private static final Log log = LogFactory.getLog(JmxTask.class);

    private static final String EVENT_TYPE = "externalEvent";
    private static final String STR_NULL = "NULL";
    private static final char FORWARD_SLASH = '/';
    static final String STREAM_NAME_PREFIX = "jmx.agent.";

    public JmxTask() {
    }

    @Override
    public void execute() {

        if (log.isDebugEnabled()) {
            log.info("Running the profile : " + this.getProperties().get(JmxConstant.JMX_PROFILE_NAME));
        }

        Map<String, String> dataMap = this.getProperties();
        //get profile name
        String profileName = dataMap.get(JmxConstant.JMX_PROFILE_NAME);

        //get the profile
        Profile profile;
        try {
            profile = new ProfileManager().getProfile(profileName);
        } catch (ProfileDoesNotExistException e) {
            log.error("Profile does not exist:" + profileName, e);
            return;
        } catch (JmxProfileException e) {
            log.error("Exception occurred: ", e);
            return;
        }

        if (profile != null) {
            //Publish the data
            try {
                //create a Jmx JmxAgent to fetch Jmx data
                JmxAgent jmxAgent = new JmxAgent(profile);
                //Create a Stream name
                String streamName = STREAM_NAME_PREFIX + profile.getName();

                //Append ".0.0 for the sake of string matching! "
                String version = Integer.toString(profile.getVersion()) + ".0.0";

                DataPublisher dataPublisher = createDataPublisher(profile);
                String streamId = dataPublisher.findStreamId(streamName, version);

                if (streamId == null) {
                    streamId = createStreamDefinition(streamName, version, jmxAgent, dataPublisher);
                }
                publishData(streamId, dataPublisher, jmxAgent, profileName);

            } catch (StreamDefinitionException e) {
                log.error("Stream definition seems to be invalid : " + e);
            } catch (AgentException e) {
                log.error(e.getErrorMessage(), e);
            } catch (MalformedURLException e) {
                log.error(e.getLocalizedMessage(), e);
            } catch (AuthenticationException e) {
                log.error(e.getErrorMessage(), e);
                //remove all the data publishers
                TenantPublisherConfigData.getDataPublisherMap().clear();
                if (log.isDebugEnabled()) {
                    log.info("Data Publisher hash table cleared");
                }
            } catch (TransportException e) {
                log.error(e);
            } catch (DifferentStreamDefinitionAlreadyDefinedException e) {
                log.error(e.getErrorMessage(), e);
            } catch (MalformedStreamDefinitionException e) {
                log.error(e.getErrorMessage(), e);
            } catch (JmxConnectionException e) {
                log.error(e.getLocalizedMessage(), e);
            } catch (JmxMBeanException e) {
                log.error(e.getLocalizedMessage(), e);
            }
        }
    }

    private DataPublisher createDataPublisher(Profile profile)
            throws AgentException, MalformedURLException, AuthenticationException, TransportException {

        String dataPublisherReceiverUrl = profile.getDpReceiverAddress();
        String dataPublisherUname = profile.getDpUserName();
        String dataPublisherPass = profile.getDpPassword();
        String dataPublisherReceiverConnectionType = profile.getDpReceiverConnectionType();
        String dataPublisherSecureConnectionType = profile.getDpSecureUrlConnectionType();
        String dataPublisherSecureUrl = profile.getDpSecureAddress();

        //get the tenant ID
        int tenantID = CarbonContext.getThreadLocalCarbonContext().getTenantId();

        //create the key for data publisher storage. Using this key, the correct data
        //publisher with the correct configuration will be returned
        String key = dataPublisherSecureConnectionType + dataPublisherSecureUrl
                + dataPublisherReceiverConnectionType + dataPublisherReceiverUrl + dataPublisherUname
                + dataPublisherPass + String.valueOf(tenantID);

        DataPublisher dataPublisher;

        //check for the availability of the data publisher
        if (TenantPublisherConfigData.getDataPublisherMap().containsKey(key)) {
            if (log.isDebugEnabled()) {
                log.info("DataPublisher exists for tenant " + tenantID);
            }

            dataPublisher = TenantPublisherConfigData.getDataPublisherMap().get(key);

        } else {
            if (log.isDebugEnabled()) {
                log.info("DataPublisher does not exist for tenant " + tenantID);
            }

            dataPublisher = new DataPublisher(dataPublisherSecureConnectionType + dataPublisherSecureUrl,
                    dataPublisherReceiverConnectionType + dataPublisherReceiverUrl, dataPublisherUname,
                    dataPublisherPass);

            TenantPublisherConfigData.getDataPublisherMap().put(key, dataPublisher);
        }

        return dataPublisher;
    }

    private void publishData(String streamId, DataPublisher dataPublisher, JmxAgent jmxAgent, String profileName)
            throws AgentException {

        ArrayList<Object> arrayList = getMBeansDetail(jmxAgent);
        if (arrayList == null) {
            return;
        }

        String host = PublisherUtil.getHostAddress();
        if ((jmxAgent.getProfile() != null) && (jmxAgent.getProfile().getUrl() != null)) {
            host = jmxAgent.getProfile().getUrl().substring(18,
                    jmxAgent.getProfile().getUrl().indexOf(FORWARD_SLASH, 19));
        }

        Event jmxEvent = new Event(streamId, System.currentTimeMillis(), new Object[] { EVENT_TYPE, host }, null,
                arrayList.toArray());
        dataPublisher.publish(jmxEvent);

        if (log.isDebugEnabled()) {
            log.info("jmx Event published for " + profileName);
        }
    }

    private ArrayList<Object> getMBeansDetail(JmxAgent jmxAgent) {
        ArrayList<Object> arrayList = new ArrayList<Object>();
        JMXConnector jmxConnector = null;

        try {
            jmxConnector = jmxAgent.openJmxConnection();

            MBean[] mBeans = jmxAgent.getProfile().getSelectedMBeans();
            Object attrValue;
            for (MBean mBean : mBeans) {
                for (MBeanAttribute mBeanAttribute : mBean.getAttributes()) {
                    // If MBean is a composite.
                    if (mBeanAttribute.getProperties() != null) {
                        CompositeData cd = (CompositeData) jmxAgent.getAttribute(jmxConnector, mBean.getMBeanName(),
                                mBeanAttribute.getAttributeName());

                        for (MBeanAttributeProperty mBeanAttributeProperty : mBeanAttribute.getProperties()) {
                            attrValue = cd.get(mBeanAttributeProperty.getPropertyName());
                            addMBeanDetail(arrayList, attrValue);
                        }
                    } else {
                        attrValue = jmxAgent.getAttribute(jmxConnector, mBean.getMBeanName(),
                                mBeanAttribute.getAttributeName());
                        addMBeanDetail(arrayList, attrValue);
                    }
                }
            }
        } catch (JmxConnectionException e) {
            log.error("Jmx Connection Exception", e);
            return null;
        } catch (JmxMBeanException e) {
            log.error("Jmx MBean exception", e);
            return null;
        } finally {
            if (jmxConnector != null) {
                try {
                    jmxAgent.closeJmxConnection(jmxConnector);
                } catch (JmxConnectionException e) {
                    log.error("Unable to close JMX connection.", e);
                }
            }
        }
        return arrayList;
    }

    private void addMBeanDetail(ArrayList<Object> arrayList, Object attrValue) {
        if (attrValue == null) {
            arrayList.add(STR_NULL);
        } else {
            if (attrValue instanceof String || attrValue instanceof Integer || attrValue instanceof Long
                    || attrValue instanceof Double || attrValue instanceof Boolean || attrValue instanceof Float) {
                arrayList.add(attrValue);
            }
        }
    }

    private String createStreamDefinition(String streamName, String version, JmxAgent jmxAgent,
            DataPublisher dataPublisher) throws MalformedURLException, StreamDefinitionException,
            DifferentStreamDefinitionAlreadyDefinedException, AgentException, MalformedStreamDefinitionException,
            JmxConnectionException, JmxMBeanException {

        StringBuilder stringBuilder = new StringBuilder();

        stringBuilder.append("{'name':'").append(streamName).append("',").append("  'version':'").append(version)
                .append("',").append("  'nickName': 'JMX Dump',").append("  'description': 'JMX monitoring data',")
                .append("  'metaData':[").append("          {'name':'clientType','type':'STRING'},")
                .append("          {'name':'host','type':'STRING'}").append("  ],").append("  'payloadData':[");

        JMXConnector jmxConnector = null;

        try {
            jmxConnector = jmxAgent.openJmxConnection();

            MBean[] mBeans = jmxAgent.getProfile().getSelectedMBeans();
            //add the attributes
            Object attrValue;
            for (MBean mBean : mBeans) {
                for (MBeanAttribute mBeanAttribute : mBean.getAttributes()) {

                    // If MBean is a composite.
                    if (mBeanAttribute.getProperties() != null) {
                        CompositeData cd = (CompositeData) jmxAgent.getAttribute(jmxConnector, mBean.getMBeanName(),
                                mBeanAttribute.getAttributeName());

                        for (MBeanAttributeProperty mBeanAttributeProperty : mBeanAttribute.getProperties()) {
                            attrValue = cd.get(mBeanAttributeProperty.getPropertyName());
                            appendColumnName(stringBuilder, attrValue, mBeanAttributeProperty.getAliasName());
                        }
                    } else {
                        attrValue = jmxAgent.getAttribute(jmxConnector, mBean.getMBeanName(),
                                mBeanAttribute.getAttributeName());
                        appendColumnName(stringBuilder, attrValue, mBeanAttribute.getAliasName());
                    }
                }
            }

            //to delete the last comma
            stringBuilder.deleteCharAt(stringBuilder.length() - 1);
            stringBuilder.append("  ]}");

        } finally {
            if (jmxConnector != null) {
                try {
                    jmxAgent.closeJmxConnection(jmxConnector);
                } catch (JmxConnectionException e) {
                    log.error("Unable to close Jmx connection.", e);
                }
            }

            return dataPublisher.defineStream(stringBuilder.toString());
        }
    }

    private void appendColumnName(StringBuilder stringBuilder, Object attrValue, String alias) {

        //if the value is a string
        if (attrValue instanceof String) {
            stringBuilder.append("{'name':'").append(alias).append("','type':'STRING'},");
        }
        //if the value is an integer
        else if (attrValue instanceof Integer) {
            stringBuilder.append("{'name':'").append(alias).append("','type':'INT'},");
        }
        //if the value is a long
        else if (attrValue instanceof Long) {
            stringBuilder.append("{'name':'").append(alias).append("','type':'LONG'},");
        }
        //if the value is a double
        else if (attrValue instanceof Double) {
            stringBuilder.append("{'name':'").append(alias).append("','type':'DOUBLE'},");
        }
        //if the value is a boolean
        else if (attrValue instanceof Boolean) {
            stringBuilder.append("{'name':'").append(alias).append("','type':'BOOL'},");
        }
        //if the value is a float
        else if (attrValue instanceof Float) {
            stringBuilder.append("{'name':'").append(alias).append("','type':'FLOAT'},");
        } else {
            log.error("Missed attribute in stream def: " + alias);
        }
    }
}