org.hyperic.hq.plugin.weblogic.jmx.WeblogicRuntimeDiscoverer.java Source code

Java tutorial

Introduction

Here is the source code for org.hyperic.hq.plugin.weblogic.jmx.WeblogicRuntimeDiscoverer.java

Source

/*
 * NOTE: This copyright does *not* cover user programs that use HQ
 * program services by normal system calls through the application
 * program interfaces provided as part of the Hyperic Plug-in Development
 * Kit or the Hyperic Client Development Kit - this is merely considered
 * normal use of the program, and does *not* fall under the heading of
 * "derived work".
 * 
 * Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
 * This file is part of HQ.
 * 
 * HQ is free software; you can redistribute it and/or modify
 * it under the terms version 2 of the GNU General Public License as
 * published by the Free Software Foundation. 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA.
 */

package org.hyperic.hq.plugin.weblogic.jmx;

import java.io.IOException;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;

import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.modelmbean.ModelMBeanInfo;
import javax.management.remote.JMXConnector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.hq.appdef.shared.AIPlatformValue;
import org.hyperic.hq.appdef.shared.AIServerExtValue;
import org.hyperic.hq.appdef.shared.AIServiceTypeValue;
import org.hyperic.hq.appdef.shared.AIServiceValue;
import org.hyperic.hq.plugin.weblogic.WeblogicAuth;
import org.hyperic.hq.plugin.weblogic.WeblogicDetector;
import org.hyperic.hq.plugin.weblogic.WeblogicMetric;
import org.hyperic.hq.plugin.weblogic.WeblogicProductPlugin;
import org.hyperic.hq.plugin.weblogic.WeblogicUtil;
import org.hyperic.hq.product.Collector;
import org.hyperic.hq.product.GenericPlugin;
import org.hyperic.hq.product.PluginException;
import org.hyperic.hq.product.PluginUpdater;
import org.hyperic.hq.product.ProductPlugin;
import org.hyperic.hq.product.RuntimeDiscoverer;
import org.hyperic.hq.product.RuntimeResourceReport;
import org.hyperic.hq.product.ServerTypeInfo;
import org.hyperic.hq.product.ServiceType;
import org.hyperic.hq.product.jmx.MBeanUtil;
import org.hyperic.hq.product.jmx.ServiceTypeFactory;
import org.hyperic.util.config.ConfigResponse;
import org.hyperic.util.config.EncodingException;

public class WeblogicRuntimeDiscoverer implements RuntimeDiscoverer, PrivilegedAction {

    private static final Double DYNAMIC_SVC_SUPPORTED_WEBLOGIC_VERSION = new Double(9.1d);

    private static final boolean useJAAS = WeblogicProductPlugin.useJAAS();
    private static final String PROP_FQDN = "weblogic.discover.fqdn";
    private static Log log = LogFactory.getLog(WeblogicRuntimeDiscoverer.class);

    private int serverId;
    private Properties props;

    private AIPlatformValue aiplatform;

    private ConfigResponse config;

    private String targetFqdn = null;

    private WeblogicDetector plugin;

    private String version;

    private ServiceTypeFactory serviceTypeFactory = new ServiceTypeFactory();

    private PluginUpdater pluginUpdater = new PluginUpdater();

    public WeblogicRuntimeDiscoverer(WeblogicDetector plugin) {
        this.plugin = plugin;
        this.version = plugin.getTypeInfo().getVersion();

        props = plugin.getManager().getProperties();

        // this property can be used to host foreign nodes on
        // another platform. if set to "same" will use the same fqdn
        // as the admin server.
        this.targetFqdn = props.getProperty(PROP_FQDN);

    }

    public WeblogicDetector getPlugin() {
        return this.plugin;
    }

    public String getPluginVersion() {
        return this.version;
    }

    public RuntimeResourceReport discoverResources(int serverId, AIPlatformValue aiplatform, ConfigResponse config)
            throws PluginException {

        if (useJAAS) {
            return discoverAs(serverId, aiplatform, config);
        } else {
            try {
                return discover(serverId, aiplatform, config);
            } catch (SecurityException e) {
                String msg = "SecurityException: " + e.getMessage();
                throw new PluginException(msg, e);
            }
        }
    }

    private RuntimeResourceReport discoverAs(int serverId, AIPlatformValue aiplatform, ConfigResponse config)
            throws PluginException {

        Object obj;
        WeblogicAuth auth = WeblogicAuth.getInstance(config.toProperties());

        this.serverId = serverId;
        this.aiplatform = aiplatform;
        this.config = config;

        try {
            obj = auth.runAs(this);
        } catch (SecurityException e) {
            throw new PluginException(e.getMessage(), e);
        }

        if (obj instanceof RuntimeResourceReport) {
            return (RuntimeResourceReport) obj;
        }

        if (obj instanceof PluginException) {
            throw (PluginException) obj;
        }

        if (obj instanceof Exception) {
            Exception e = (Exception) obj;
            throw new PluginException(e.getMessage(), e);
        }

        throw new IllegalArgumentException();
    }

    public Object run() {
        try {
            return discover(this.serverId, this.aiplatform, this.config);
        } catch (Exception e) {
            return e;
        }
    }

    private RuntimeResourceReport discover(int serverId, AIPlatformValue aiplatform, ConfigResponse config)
            throws PluginException {

        String installpath = config.getValue(ProductPlugin.PROP_INSTALLPATH);
        // incase jaas is disabled; generatePlatform may use this.
        this.aiplatform = aiplatform;

        log.debug("discover using: " + config);

        String domainName = config.getValue(WeblogicMetric.PROP_DOMAIN);
        String serverName = config.getValue(WeblogicMetric.PROP_SERVER);

        RuntimeResourceReport rrr = new RuntimeResourceReport(serverId);

        Properties props = config.toProperties();

        WeblogicDiscover discover = new WeblogicDiscover(this.version, props);

        try {
            MBeanServer mServer = discover.getMBeanServer();

            discover.init(mServer);

            NodeManagerQuery nodemgrQuery = new NodeManagerQuery();
            ServerQuery serverQuery = new ServerQuery();
            serverQuery.setDiscover(discover);

            ArrayList servers = new ArrayList();

            discover.find(mServer, serverQuery, servers);

            WeblogicQuery[] serviceQueries = discover.getServiceQueries();

            // ensure admin is first incase we need version
            serverQuery.sort(servers);

            String adminVersion = null;

            for (int i = 0; i < servers.size(); i++) {
                serverQuery = (ServerQuery) servers.get(i);
                if (!serverQuery.isRunning())
                    continue;

                if (serverQuery.isAdmin()) {
                    adminVersion = serverQuery.getVersion();
                } else if (serverQuery.getVersion() == null) {
                    // will be the case if a server was create but never started
                    // safely assume it was created by the admin server in this
                    // case and hence is the same version.
                    serverQuery.setVersion(adminVersion);
                }

                AIPlatformValue aPlatform;
                AIServerExtValue aServer = generateServer(serverQuery);

                // Set the ID, so when this report is processed at the server,
                // there is no mistaking this server in the report for any other
                // server
                // in appdef (or worse, not matching anything and adding a new
                // server).
                if (serverQuery.getName().equals(serverName)
                        && serverQuery.getDiscover().getDomain().equals(domainName)) {
                    aServer.setId(new Integer(serverId));
                    aServer.setPlaceholder(true);
                    // maintain existing installpath,
                    // MBeanServer CurrentDirectory might be different
                    if (installpath != null) {
                        aServer.setInstallPath(installpath);
                    }
                    aiplatform.addAIServerValue(aServer);
                    rrr.addAIPlatform(aiplatform);
                } else {
                    aPlatform = generatePlatform(serverQuery);
                    aPlatform.addAIServerValue(aServer);
                    rrr.addAIPlatform(aPlatform);
                }

                if (!serverQuery.isRunning()) {
                    continue;
                }

                mServer = discover.getMBeanServer(serverQuery.getUrl());

                ArrayList aServices = new ArrayList();
                ArrayList services = new ArrayList();

                for (int j = 0; j < serviceQueries.length; j++) {
                    WeblogicQuery serviceQuery = serviceQueries[j];

                    serviceQuery.setParent(serverQuery);
                    serviceQuery.setVersion(serverQuery.getVersion());

                    discover.find(mServer, serviceQuery, services);
                }

                // Dynamic services can only be discovered on WebLogic 9.1 or
                // higher
                if (DYNAMIC_SVC_SUPPORTED_WEBLOGIC_VERSION
                        .compareTo(Double.valueOf(serverQuery.getVersion())) <= 0) {
                    final JMXConnector jmxConnector = WeblogicUtil.getManagedServerConnection(props);
                    Set serviceTypes = new HashSet();
                    try {
                        discoverDynamicServices(discover, jmxConnector.getMBeanServerConnection(), serverQuery,
                                services, serviceTypes);
                    } catch (IOException e) {
                        throw new PluginException("Error discovering dynamic services", e);
                    } finally {
                        try {
                            jmxConnector.close();
                        } catch (IOException e) {
                        }
                    }
                    final AIServiceTypeValue[] serviceTypeValues = new AIServiceTypeValue[serviceTypes.size()];
                    int count = 0;
                    for (Iterator iterator = serviceTypes.iterator(); iterator.hasNext();) {
                        serviceTypeValues[count] = ((ServiceType) iterator.next()).getAIServiceTypeValue();
                        count++;
                    }
                    aServer.setAiServiceTypes(serviceTypeValues);
                    pluginUpdater.updateServiceTypes(plugin.getProductPlugin(), serviceTypes);
                }

                for (int k = 0; k < services.size(); k++) {
                    boolean valid = true;
                    ServiceQuery service = (ServiceQuery) services.get(k);
                    if (service instanceof ApplicationQuery) {
                        valid = ((ApplicationQuery) service).isEAR();
                    }
                    if (valid) {
                        aServices.add(generateService(service));

                    } else {
                        log.debug("skipped service:" + service.getName());
                    }
                }

                AIServiceValue[] aiservices = (AIServiceValue[]) aServices.toArray(new AIServiceValue[0]);
                aServer.setAIServiceValues(aiservices);

                if (serverQuery.isAdmin()) {
                    ArrayList mgrs = new ArrayList();
                    nodemgrQuery.setAdminServer(serverQuery);
                    discover.find(mServer, nodemgrQuery, mgrs);

                    for (int n = 0; n < mgrs.size(); n++) {
                        nodemgrQuery = (NodeManagerQuery) mgrs.get(n);
                        aServer = generateServer(nodemgrQuery);
                        aPlatform = generatePlatform(nodemgrQuery);
                        aPlatform.addAIServerValue(aServer);
                        rrr.addAIPlatform(aPlatform);
                    }
                }
            }
        } catch (WeblogicDiscoverException e) {
            throw new PluginException(e.getMessage(), e);
        }

        return rrr;
    }

    private void discoverDynamicServices(WeblogicDiscover discover, MBeanServerConnection mServer,
            ServerQuery parent, ArrayList services, Set serviceTypes)
            throws PluginException, WeblogicDiscoverException {
        try {
            final Set objectNames = mServer.queryNames(new ObjectName(MBeanUtil.DYNAMIC_SERVICE_DOMAIN + ":*"),
                    null);
            //Only WebLogic Admin servers have auto-inventory plugins - have to construct a ServerInfo for the WebLogic server
            String[] platformTypes = ((ServerTypeInfo) plugin.getTypeInfo()).getPlatformTypes();
            ServerTypeInfo server = new ServerTypeInfo(parent.getResourceType(), parent.getDescription(),
                    parent.getVersion());
            server.setValidPlatformTypes(platformTypes);
            for (Iterator iterator = objectNames.iterator(); iterator.hasNext();) {
                final ObjectName objectName = (ObjectName) iterator.next();
                final MBeanInfo serviceInfo = mServer.getMBeanInfo(objectName);
                if (serviceInfo instanceof ModelMBeanInfo) {
                    ServiceType identityType = serviceTypeFactory.getServiceType(
                            plugin.getProductPlugin().getName(), server, (ModelMBeanInfo) serviceInfo, objectName);
                    //identityType could be null if MBean is not to be exported
                    if (identityType != null) {
                        ServiceType serviceType;
                        if (!serviceTypes.contains(identityType)) {
                            serviceType = serviceTypeFactory.create(plugin.getProductPlugin(), server,
                                    (ModelMBeanInfo) serviceInfo, objectName);
                            if (serviceType != null) {
                                serviceTypes.add(serviceType);
                            }
                        } else {
                            serviceType = findServiceType(identityType.getInfo().getName(), serviceTypes);
                        }
                        final String shortServiceType = identityType.getServiceName();
                        DynamicServiceQuery dynamicServiceQuery = new DynamicServiceQuery();
                        dynamicServiceQuery.setParent(parent);
                        dynamicServiceQuery.setType(shortServiceType);
                        dynamicServiceQuery.setAttributeNames(serviceType.getCustomProperties().getOptionNames());
                        dynamicServiceQuery.setName(objectName.getKeyProperty("name"));
                        dynamicServiceQuery.getDynamicAttributes(mServer, objectName);
                        services.add(dynamicServiceQuery);
                    }
                }
            }
        } catch (Exception e) {
            throw new PluginException(e.getMessage(), e);
        }
    }

    private ServiceType findServiceType(String serviceName, Set serviceTypes) {
        for (Iterator iterator = serviceTypes.iterator(); iterator.hasNext();) {
            ServiceType serviceType = (ServiceType) iterator.next();
            if (serviceType.getInfo().getName().equals(serviceName)) {
                return serviceType;
            }
        }
        return null;
    }

    private AIPlatformValue generatePlatform(BaseServerQuery server) {

        AIPlatformValue aiplatform = new AIPlatformValue();

        String serverFqdn = server.getFqdn();
        serverFqdn = //support mapping via agent.properties
                this.props.getProperty(PROP_FQDN + "." + serverFqdn, serverFqdn);
        String fqdn = serverFqdn;

        // let it be known if the platform does not exist in cam
        // since ai will ka-boom with huge "No such entity!" stacktrace.
        // XXX ai should handle this condition better
        if (!fqdn.equals(this.aiplatform.getFqdn())) {
            log.info("Discovered server (" + server.getResourceFullName() + ") hosted on another platform (fqdn="
                    + fqdn + ")");
        }

        if (this.targetFqdn != null) {
            if (this.targetFqdn.equals("same")) {
                fqdn = this.aiplatform.getFqdn();
            } else {
                fqdn = this.targetFqdn;
            }
        } else {
            // out-of-the-box weblogic w/o changing ListenAddress
            if (serverFqdn.equals("localhost") || serverFqdn.equals("127.0.0.1")) {
                fqdn = this.aiplatform.getFqdn();
            } else {
                fqdn = serverFqdn;
            }
        }

        if (!fqdn.equals(serverFqdn)) {
            log.info("changing fqdn for " + server.getName() + ": " + serverFqdn + " => " + fqdn);
        }

        aiplatform.setFqdn(fqdn);

        return aiplatform;
    }

    private AIServerExtValue generateServer(BaseServerQuery server) throws PluginException {

        AIServerExtValue aiserver = new AIServerExtValue();

        aiserver.setInstallPath(server.getInstallPath());
        aiserver.setAutoinventoryIdentifier(server.getIdentifier());

        aiserver.setServicesAutomanaged(true);
        aiserver.setServerTypeName(server.getResourceName());
        String name = server.getResourceFullName();
        if (WeblogicProductPlugin.usePlatformName) {
            name = GenericPlugin.getPlatformName() + " " + name;
        }
        aiserver.setName(name);
        String notes = server.getDescription();
        if (notes != null) {
            aiserver.setDescription(notes);
        }
        if (!server.isAdmin()) {
            ConfigResponse productConfig = new ConfigResponse(server.getResourceConfig());
            String listeningPorts = server.getAttribute(BaseServerQuery.ATTR_LISTEN_PORT);
            if (listeningPorts != null && !listeningPorts.equals("")) {
                productConfig.setValue(Collector.LISTEN_PORTS, listeningPorts);
            }
            ConfigResponse metricConfig = new ConfigResponse();
            ConfigResponse cprops = new ConfigResponse(server.getCustomProperties());

            try {
                if (server.hasControl() && !server.isServer61()) {
                    ConfigResponse controlConfig = new ConfigResponse(server.getControlConfig());
                    aiserver.setControlConfig(controlConfig.encode());
                }

                aiserver.setProductConfig(productConfig.encode());
                aiserver.setMeasurementConfig(metricConfig.encode());
                aiserver.setCustomProperties(cprops.encode());
            } catch (EncodingException e) {
                throw new PluginException("Error generating config", e);
            }
        }

        log.debug("discovered server: " + aiserver.getName());

        return aiserver;
    }

    private AIServiceValue generateService(ServiceQuery service) throws PluginException {
        AIServiceValue aiservice = new AIServiceValue();

        ConfigResponse productConfig = new ConfigResponse(service.getResourceConfig());
        ConfigResponse metricConfig = new ConfigResponse();
        ConfigResponse cprops = new ConfigResponse(service.getCustomProperties());

        String notes = service.getDescription();
        if (notes != null) {
            aiservice.setDescription(notes);
        }

        aiservice.setServiceTypeName(service.getResourceName());

        String name = service.getResourceFullName();
        if (WeblogicProductPlugin.usePlatformName) {
            name = GenericPlugin.getPlatformName() + " " + name;
        }
        if (name.length() >= 200) {
            // make sure we dont exceed service name limit
            name = name.substring(0, 199);
        }
        aiservice.setName(name);

        try {
            if (service.hasControl() && !service.isServer61()) {
                ConfigResponse controlConfig = new ConfigResponse(service.getControlConfig());
                aiservice.setControlConfig(controlConfig.encode());
            }

            aiservice.setProductConfig(productConfig.encode());
            aiservice.setMeasurementConfig(metricConfig.encode());
            aiservice.setCustomProperties(cprops.encode());

            if (service.hasResponseTime()) {
                ConfigResponse rtConfig = new ConfigResponse(service.getResponseTimeConfig());
                aiservice.setResponseTimeConfig(rtConfig.encode());
            }
        } catch (EncodingException e) {
            throw new PluginException("Error generating config", e);
        }

        log.debug("discovered service: " + aiservice.getName());

        return aiservice;
    }
}