org.opennms.netmgt.provision.service.vmware.VmwareRequisitionUrlConnection.java Source code

Java tutorial

Introduction

Here is the source code for org.opennms.netmgt.provision.service.vmware.VmwareRequisitionUrlConnection.java

Source

/*******************************************************************************
 * This file is part of OpenNMS(R).
 *
 * Copyright (C) 2013-2014 The OpenNMS Group, Inc.
 * OpenNMS(R) is Copyright (C) 1999-2014 The OpenNMS Group, Inc.
 *
 * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
 *
 * OpenNMS(R) is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * OpenNMS(R) 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with OpenNMS(R).  If not, see:
 *      http://www.gnu.org/licenses/
 *
 * For more information contact:
 *     OpenNMS(R) Licensing <license@opennms.org>
 *     http://www.opennms.org/
 *     http://www.opennms.com/
 *******************************************************************************/

package org.opennms.netmgt.provision.service.vmware;

import com.vmware.vim25.*;
import com.vmware.vim25.mo.*;

import org.apache.commons.io.IOExceptionWithCause;
import org.apache.commons.lang.StringUtils;
import org.apache.http.conn.util.InetAddressUtils;
import org.exolab.castor.xml.MarshalException;
import org.exolab.castor.xml.ValidationException;
import org.opennms.core.spring.BeanUtils;
import org.opennms.core.utils.url.GenericURLConnection;
import org.opennms.core.xml.JaxbUtils;
import org.opennms.netmgt.model.PrimaryType;
import org.opennms.netmgt.provision.persist.ForeignSourceRepository;
import org.opennms.netmgt.provision.persist.requisition.*;
import org.opennms.protocols.vmware.VmwareViJavaAccess;
import org.sblim.wbem.cim.CIMException;
import org.sblim.wbem.cim.CIMObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.bind.JAXBException;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.*;
import java.rmi.RemoteException;
import java.util.*;

/**
 * The Class VmwareRequisitionUrlConnection
 * 
 * <p>This class is used for the automtic requisition of Vmware related entities.</p>
 *
 * @author Christian Pape <Christian.Pape@informatik.hs-fulda.de>
 * @author Alejandro Galue <agalue@opennms.org>
 */
public class VmwareRequisitionUrlConnection extends GenericURLConnection {
    /**
     * the logger
     */
    private Logger logger = LoggerFactory.getLogger(VmwareRequisitionUrlConnection.class);

    private static final String VMWARE_HOSTSYSTEM_SERVICES = "hostSystemServices";
    private static final String VMWARE_VIRTUALMACHINE_SERVICES = "virtualMachineServices";

    private String[] m_hostSystemServices;
    private String[] m_virtualMachineServices;

    private String m_hostname = null;
    private String m_username = null;
    private String m_password = null;
    protected String m_foreignSource = null;

    private boolean m_importVMPoweredOn = true;
    private boolean m_importVMPoweredOff = false;
    private boolean m_importVMSuspended = false;

    private boolean m_importHostPoweredOn = true;
    private boolean m_importHostPoweredOff = false;
    private boolean m_importHostStandBy = false;
    private boolean m_importHostUnknown = false;

    private boolean m_persistIPv4 = true;
    private boolean m_persistIPv6 = true;

    private boolean m_persistVMs = true;
    private boolean m_persistHosts = true;

    private boolean m_topologyPortGroups = false;
    private boolean m_topologyNetworks = true;
    private boolean m_topologyDatastores = true;

    /*
     * Host system managedObjectId to name mapping
     */

    private Map<String, String> m_hostSystemMap = new HashMap<String, String>();

    /**
     * the query arguments
     */
    private Map<String, String> m_args = null;

    /**
     * requisition object
     */
    private Requisition m_requisition = null;

    /**
     * Constructor for creating an instance of this class.
     *
     * @param url the URL to use
     * @throws MalformedURLException
     * @throws RemoteException
     */
    public VmwareRequisitionUrlConnection(URL url) throws MalformedURLException, RemoteException {
        super(url);

        m_hostname = url.getHost();

        m_username = getUsername();
        m_password = getPassword();

        m_args = getQueryArgs();

        boolean importVMOnly = queryParameter("importVMOnly", false);
        boolean importHostOnly = queryParameter("importHostOnly", false);

        if (importHostOnly && importVMOnly) {
            throw new MalformedURLException("importHostOnly and importVMOnly can't be true simultaneously");
        }
        if (importHostOnly) {
            m_persistVMs = false;
        }
        if (importVMOnly) {
            m_persistHosts = false;
        }

        boolean importIPv4Only = queryParameter("importIPv4Only", false);
        boolean importIPv6Only = queryParameter("importIPv6Only", false);

        if (importIPv4Only && importIPv6Only) {
            throw new MalformedURLException("importIPv4Only and importIPv6Only can't be true simultaneously");
        }
        if (importIPv4Only) {
            m_persistIPv6 = false;
        }
        if (importIPv6Only) {
            m_persistIPv4 = false;
        }

        m_topologyPortGroups = queryParameter("topologyPortGroups", false);
        m_topologyNetworks = queryParameter("topologyNetworks", true);
        m_topologyDatastores = queryParameter("topologyDatastores", true);

        m_importVMPoweredOn = queryParameter("importVMPoweredOn", true);
        m_importVMPoweredOff = queryParameter("importVMPoweredOff", false);
        m_importVMSuspended = queryParameter("importVMSuspended", false);

        m_importHostPoweredOn = queryParameter("importHostPoweredOn", true);
        m_importHostPoweredOff = queryParameter("importHostPoweredOff", false);
        m_importHostStandBy = queryParameter("importHostStandBy", false);
        m_importHostUnknown = queryParameter("importHostUnknown", false);

        if (queryParameter("importHostAll", false)) {
            m_importHostPoweredOn = true;
            m_importHostPoweredOff = true;
            m_importHostStandBy = true;
            m_importHostUnknown = true;
        }

        if (queryParameter("importVMAll", false)) {
            m_importVMPoweredOff = true;
            m_importVMPoweredOn = true;
            m_importVMSuspended = true;
        }

        String path = url.getPath();

        path = path.replaceAll("^/", "");
        path = path.replaceAll("/$", "");

        String[] pathElements = path.split("/");

        if (pathElements.length == 1) {
            if ("".equals(pathElements[0])) {
                m_foreignSource = "vmware-" + m_hostname;
            } else {
                m_foreignSource = pathElements[0];
            }
        } else {
            throw new MalformedURLException(
                    "Error processing path element of URL (vmware://username:password@host[/foreign-source]?keyA=valueA;keyB=valueB;...)");
        }
    }

    /**
     * Returns a boolean representation for a given on/off parameter.
     *
     * @param key          the parameter's name
     * @param defaultValue the default value to use
     * @return the boolean value
     */
    private boolean queryParameter(String key, boolean defaultValue) {
        if (m_args.get(key) == null) {
            return defaultValue;
        } else {
            String value = m_args.get(key).toLowerCase();

            return ("yes".equals(value) || "true".equals(value) || "on".equals(value) || "1".equals(value));
        }
    }

    @Override
    public void connect() throws IOException {
        // To change body of implemented methods use File | Settings | File
        // Templates.
    }

    private boolean reachableCimService(VmwareViJavaAccess vmwareViJavaAccess, HostSystem hostSystem,
            String ipAddress) {
        if (!vmwareViJavaAccess.setTimeout(3000)) {
            logger.warn("Error setting connection timeout");
        }

        List<CIMObject> cimObjects = null;
        try {
            cimObjects = vmwareViJavaAccess.queryCimObjects(hostSystem, "CIM_NumericSensor", ipAddress);
        } catch (ConnectException e) {
            return false;
        } catch (RemoteException e) {
            return false;
        } catch (CIMException e) {
            return false;
        }

        return cimObjects != null;
    }

    /**
     * Creates a requisition node for the given managed entity and type.
     *
     * @param ipAddresses   the set of Ip addresses
     * @param managedEntity the managed entity
     * @return the generated requisition node
     */
    private RequisitionNode createRequisitionNode(Set<String> ipAddresses, ManagedEntity managedEntity,
            int apiVersion, VmwareViJavaAccess vmwareViJavaAccess) {
        RequisitionNode requisitionNode = new RequisitionNode();

        // Setting the node label
        requisitionNode.setNodeLabel(managedEntity.getName());

        // Foreign Id consisting of managed entity Id
        requisitionNode.setForeignId(managedEntity.getMOR().getVal());

        /*
         * Original version:
         *
         * Foreign Id consisting of VMware management server's hostname and managed entity id
         *
         * requisitionNode.setForeignId(m_hostname + "/" + managedEntity.getMOR().getVal());
         */

        if (managedEntity instanceof VirtualMachine) {
            boolean firstInterface = true;

            // add all given interfaces
            for (String ipAddress : ipAddresses) {

                try {
                    if ((m_persistIPv4 && InetAddressUtils.isIPv4Address(ipAddress))
                            || (m_persistIPv6 && InetAddressUtils.isIPv6Address(ipAddress))) {
                        InetAddress inetAddress = InetAddress.getByName(ipAddress);

                        if (!inetAddress.isLoopbackAddress()) {
                            RequisitionInterface requisitionInterface = new RequisitionInterface();
                            requisitionInterface.setIpAddr(ipAddress);

                            //  the first one will be primary
                            if (firstInterface) {
                                requisitionInterface.setSnmpPrimary(PrimaryType.PRIMARY);
                                for (String service : m_virtualMachineServices) {
                                    requisitionInterface.insertMonitoredService(
                                            new RequisitionMonitoredService(service.trim()));
                                }
                                firstInterface = false;
                            } else {
                                requisitionInterface.setSnmpPrimary(PrimaryType.SECONDARY);
                            }

                            requisitionInterface.setManaged(Boolean.TRUE);
                            requisitionInterface.setStatus(Integer.valueOf(1));
                            requisitionNode.putInterface(requisitionInterface);
                        }
                    }
                } catch (UnknownHostException unknownHostException) {
                    logger.warn("Invalid IP address '{}'", unknownHostException.getMessage());
                }
            }
        } else {
            if (managedEntity instanceof HostSystem) {
                boolean reachableInterfaceFound = false, firstInterface = true;
                List<RequisitionInterface> requisitionInterfaceList = new ArrayList<RequisitionInterface>();
                RequisitionInterface primaryInterfaceCandidate = null;

                // add all given interfaces
                for (String ipAddress : ipAddresses) {

                    try {
                        if ((m_persistIPv4 && InetAddressUtils.isIPv4Address(ipAddress))
                                || (m_persistIPv6 && InetAddressUtils.isIPv6Address(ipAddress))) {
                            InetAddress inetAddress = InetAddress.getByName(ipAddress);

                            if (!inetAddress.isLoopbackAddress()) {
                                RequisitionInterface requisitionInterface = new RequisitionInterface();
                                requisitionInterface.setIpAddr(ipAddress);

                                if (firstInterface) {
                                    primaryInterfaceCandidate = requisitionInterface;
                                    firstInterface = false;
                                }

                                if (!reachableInterfaceFound && reachableCimService(vmwareViJavaAccess,
                                        (HostSystem) managedEntity, ipAddress)) {
                                    primaryInterfaceCandidate = requisitionInterface;
                                    reachableInterfaceFound = true;
                                }

                                requisitionInterface.setManaged(Boolean.TRUE);
                                requisitionInterface.setStatus(Integer.valueOf(1));
                                requisitionInterface.setSnmpPrimary(PrimaryType.SECONDARY);
                                requisitionInterfaceList.add(requisitionInterface);
                            }
                        }

                    } catch (UnknownHostException unknownHostException) {
                        logger.warn("Invalid IP address '{}'", unknownHostException.getMessage());
                    }
                }

                if (primaryInterfaceCandidate != null) {
                    if (reachableInterfaceFound) {
                        logger.warn("Found reachable primary interface '{}'",
                                primaryInterfaceCandidate.getIpAddr());
                    } else {
                        logger.warn(
                                "Only non-reachable interfaces found, using first one for primary interface '{}'",
                                primaryInterfaceCandidate.getIpAddr());
                    }
                    primaryInterfaceCandidate.setSnmpPrimary(PrimaryType.PRIMARY);

                    for (String service : m_hostSystemServices) {
                        if (reachableInterfaceFound || !"VMwareCim-HostSystem".equals(service)) {
                            primaryInterfaceCandidate
                                    .insertMonitoredService(new RequisitionMonitoredService(service.trim()));
                        }
                    }
                } else {
                    logger.warn("No primary interface found");
                }

                for (RequisitionInterface requisitionInterface : requisitionInterfaceList) {
                    requisitionNode.putInterface(requisitionInterface);
                }

            } else {
                logger.error("Undefined type of managedEntity '{}'", managedEntity.getMOR().getType());
                return null;
            }
        }

        /*
         * For now we use displaycategory, notifycategory and pollercategory for storing
         * the vcenter Ip address, the username and the password
         */

        String powerState = "unknown";
        StringBuffer vmwareTopologyInfo = new StringBuffer();

        // putting parents to topology information
        ManagedEntity parentEntity = managedEntity.getParent();

        do {
            if (vmwareTopologyInfo.length() > 0) {
                vmwareTopologyInfo.append(", ");
            }
            try {
                if (parentEntity != null && parentEntity.getMOR() != null) {
                    vmwareTopologyInfo.append(parentEntity.getMOR().getVal() + "/"
                            + URLEncoder.encode(parentEntity.getName(), "UTF-8"));
                } else {
                    logger.warn(
                            "Can't add topologyInformation because either the parentEntity or the MOR is null for "
                                    + managedEntity.getName());
                }
            } catch (UnsupportedEncodingException e) {
                logger.warn("Unsupported encoding '{}'", e.getMessage());
            }
            parentEntity = parentEntity == null ? null : parentEntity.getParent();
        } while (parentEntity != null);

        if (managedEntity instanceof HostSystem) {

            HostSystem hostSystem = (HostSystem) managedEntity;

            HostRuntimeInfo hostRuntimeInfo = hostSystem.getRuntime();

            if (hostRuntimeInfo == null) {
                logger.debug("hostRuntimeInfo=null");
            } else {
                HostSystemPowerState hostSystemPowerState = hostRuntimeInfo.getPowerState();
                if (hostSystemPowerState == null) {
                    logger.debug("hostSystemPowerState=null");
                } else {
                    powerState = hostSystemPowerState.toString();
                }
            }

            try {
                if (m_topologyDatastores) {
                    for (Datastore datastore : hostSystem.getDatastores()) {
                        if (vmwareTopologyInfo.length() > 0) {
                            vmwareTopologyInfo.append(", ");
                        }
                        try {
                            vmwareTopologyInfo.append(datastore.getMOR().getVal() + "/"
                                    + URLEncoder.encode(datastore.getSummary().getName(), "UTF-8"));
                        } catch (UnsupportedEncodingException e) {
                            logger.warn("Unsupported encoding '{}'", e.getMessage());
                        }
                    }
                }
            } catch (RemoteException e) {
                logger.warn("Cannot retrieve datastores for managedEntity '{}': '{}'",
                        managedEntity.getMOR().getVal(), e.getMessage());
            }

            try {
                if (m_topologyNetworks) {
                    for (Network network : hostSystem.getNetworks()) {
                        if (vmwareTopologyInfo.length() > 0) {
                            vmwareTopologyInfo.append(", ");
                        }
                        try {
                            if (network instanceof DistributedVirtualPortgroup ? m_topologyPortGroups : true) {
                                vmwareTopologyInfo.append(network.getMOR().getVal() + "/"
                                        + URLEncoder.encode(network.getSummary().getName(), "UTF-8"));
                            }
                        } catch (UnsupportedEncodingException e) {
                            logger.warn("Unsupported encoding '{}'", e.getMessage());
                        }
                    }
                }
            } catch (RemoteException e) {
                logger.warn("Cannot retrieve networks for managedEntity '{}': '{}'",
                        managedEntity.getMOR().getVal(), e.getMessage());
            }
        } else {

            if (managedEntity instanceof VirtualMachine) {
                VirtualMachine virtualMachine = (VirtualMachine) managedEntity;

                VirtualMachineRuntimeInfo virtualMachineRuntimeInfo = virtualMachine.getRuntime();

                if (virtualMachineRuntimeInfo == null) {
                    logger.debug("virtualMachineRuntimeInfo=null");
                } else {
                    VirtualMachinePowerState virtualMachinePowerState = virtualMachineRuntimeInfo.getPowerState();
                    if (virtualMachinePowerState == null) {
                        logger.debug("virtualMachinePowerState=null");
                    } else {
                        powerState = virtualMachinePowerState.toString();
                    }
                }

                try {
                    if (m_topologyDatastores) {
                        for (Datastore datastore : virtualMachine.getDatastores()) {
                            if (vmwareTopologyInfo.length() > 0) {
                                vmwareTopologyInfo.append(", ");
                            }
                            try {
                                vmwareTopologyInfo.append(datastore.getMOR().getVal() + "/"
                                        + URLEncoder.encode(datastore.getSummary().getName(), "UTF-8"));
                            } catch (UnsupportedEncodingException e) {
                                logger.warn("Unsupported encoding '{}'", e.getMessage());
                            }
                        }
                    }
                } catch (RemoteException e) {
                    logger.warn("Cannot retrieve datastores for managedEntity '{}': '{}'",
                            managedEntity.getMOR().getVal(), e.getMessage());
                }
                try {
                    if (m_topologyNetworks) {
                        for (Network network : virtualMachine.getNetworks()) {
                            if (vmwareTopologyInfo.length() > 0) {
                                vmwareTopologyInfo.append(", ");
                            }
                            try {
                                if (network instanceof DistributedVirtualPortgroup ? m_topologyPortGroups : true) {
                                    vmwareTopologyInfo.append(network.getMOR().getVal() + "/"
                                            + URLEncoder.encode(network.getSummary().getName(), "UTF-8"));
                                }
                            } catch (UnsupportedEncodingException e) {
                                logger.warn("Unsupported encoding '{}'", e.getMessage());
                            }
                        }
                    }
                } catch (RemoteException e) {
                    logger.warn("Cannot retrieve networks for managedEntity '{}': '{}'",
                            managedEntity.getMOR().getVal(), e.getMessage());
                }

                if (vmwareTopologyInfo.length() > 0) {
                    vmwareTopologyInfo.append(", ");
                }

                try {
                    vmwareTopologyInfo.append(virtualMachine.getRuntime().getHost().getVal() + "/" + URLEncoder
                            .encode(m_hostSystemMap.get(virtualMachine.getRuntime().getHost().getVal()), "UTF-8"));
                } catch (UnsupportedEncodingException e) {
                    logger.warn("Unsupported encoding '{}'", e.getMessage());
                }
            } else {
                logger.error("Undefined type of managedEntity '{}'", managedEntity.getMOR().getType());

                return null;
            }
        }

        RequisitionAsset requisitionAssetHostname = new RequisitionAsset("vmwareManagementServer", m_hostname);
        requisitionNode.putAsset(requisitionAssetHostname);

        RequisitionAsset requisitionAssetType = new RequisitionAsset("vmwareManagedEntityType",
                (managedEntity instanceof HostSystem ? "HostSystem" : "VirtualMachine"));
        requisitionNode.putAsset(requisitionAssetType);

        RequisitionAsset requisitionAssetId = new RequisitionAsset("vmwareManagedObjectId",
                managedEntity.getMOR().getVal());
        requisitionNode.putAsset(requisitionAssetId);

        RequisitionAsset requisitionAssetTopologyInfo = new RequisitionAsset("vmwareTopologyInfo",
                vmwareTopologyInfo.toString());
        requisitionNode.putAsset(requisitionAssetTopologyInfo);

        RequisitionAsset requisitionAssetState = new RequisitionAsset("vmwareState", powerState);
        requisitionNode.putAsset(requisitionAssetState);

        requisitionNode.putCategory(new RequisitionCategory("VMware" + apiVersion));

        return requisitionNode;
    }

    /**
     * Builds the complete requisition object.
     *
     * @return the requisition object
     */
    private Requisition buildVMwareRequisition() {
        VmwareViJavaAccess vmwareViJavaAccess = null;

        // for now, set the foreign source to the specified vcenter host
        m_requisition = new Requisition(m_foreignSource);

        logger.debug("Creating new VIJava access object for host {} ...", m_hostname);
        if ((m_username == null || "".equals(m_username)) || (m_password == null || "".equals(m_password))) {
            try {
                vmwareViJavaAccess = new VmwareViJavaAccess(m_hostname);
            } catch (MarshalException e) {
                logger.warn("Error initialising VMware connection to '{}': '{}'", m_hostname, e.getMessage());
                return null;
            } catch (ValidationException e) {
                logger.warn("Error initialising VMware connection to '{}': '{}'", m_hostname, e.getMessage());
                return null;
            } catch (IOException e) {
                logger.warn("Error initialising VMware connection to '{}': '{}'", m_hostname, e.getMessage());
                return null;
            }
        } else {
            vmwareViJavaAccess = new VmwareViJavaAccess(m_hostname, m_username, m_password);
        }
        logger.debug("Successfully created new VIJava access object for host {}", m_hostname);

        logger.debug("Connecting VIJava access for host {} ...", m_hostname);
        try {
            vmwareViJavaAccess.connect();
        } catch (MalformedURLException e) {
            logger.warn("Error connecting VMware management server '{}': '{}'", m_hostname, e.getMessage());
            return null;
        } catch (RemoteException e) {
            logger.warn("Error connecting VMware management server '{}': '{}'", m_hostname, e.getMessage());
            return null;
        }
        logger.debug("Successfully connected VIJava access for host {}", m_hostname);

        logger.debug("Starting to enumerate VMware managed objects from host {} ...", m_hostname);
        try {
            int apiVersion = vmwareViJavaAccess.getMajorApiVersion();

            // get services to be added to host systems
            // m_hostSystemServices = getHostSystemServices(apiVersion);

            if (m_args != null && m_args.get(VMWARE_HOSTSYSTEM_SERVICES) != null) {
                m_hostSystemServices = m_args.get(VMWARE_HOSTSYSTEM_SERVICES).split(",");
            } else {
                m_hostSystemServices = new String[] { "VMware-ManagedEntity", "VMware-HostSystem",
                        "VMwareCim-HostSystem" };
            }

            // get services to be added to virtual machines
            // m_virtualMachineServices = getVirtualMachineServices(apiVersion);

            if (m_args != null && m_args.get(VMWARE_VIRTUALMACHINE_SERVICES) != null) {
                m_virtualMachineServices = m_args.get(VMWARE_VIRTUALMACHINE_SERVICES).split(",");
            } else {
                m_virtualMachineServices = new String[] { "VMware-ManagedEntity", "VMware-VirtualMachine" };
            }

            logger.debug("Starting to iterate host system managed objects from host {} ...", m_hostname);
            iterateHostSystems(vmwareViJavaAccess, apiVersion);
            logger.debug("Done iterating host system managed objects from host {}", m_hostname);
            logger.debug("Starting to iterate VM managed objects from host {} ...", m_hostname);
            iterateVirtualMachines(vmwareViJavaAccess, apiVersion);
            logger.debug("Done iterating VM managed objects from host {}", m_hostname);
        } catch (RemoteException e) {
            logger.warn("Error retrieving managed objects from VMware management server '{}': '{}'", m_hostname,
                    e.getMessage());
            return null;
        } finally {
            vmwareViJavaAccess.disconnect();
        }

        return m_requisition;
    }

    /**
     * Checks whether the host system should be imported into the requisition.
     *
     * @param hostSystem the system to check
     * @return true for import, false otherwise
     */
    private boolean checkHostPowerState(HostSystem hostSystem) {
        logger.debug("Checking power state for host system {} (ID {})", hostSystem.getName(),
                hostSystem.getMOR().getVal());
        String powerState = hostSystem.getRuntime().getPowerState().toString();

        if ("poweredOn".equals(powerState) && m_importHostPoweredOn) {
            return true;
        }
        if ("poweredOff".equals(powerState) && m_importHostPoweredOff) {
            return true;
        }
        if ("standBy".equals(powerState) && m_importHostStandBy) {
            return true;
        }
        if ("unknown".equals(powerState) && m_importHostUnknown) {
            return true;
        }

        return false;
    }

    /**
     * Checks whether the virtual machine should be imported into the requisition.
     *
     * @param virtualMachine the system to check
     * @return true for import, false otherwise
     */
    private boolean checkVMPowerState(VirtualMachine virtualMachine) {
        logger.debug("Checking power state for VM {} (ID: {})", virtualMachine.getName(),
                virtualMachine.getMOR().getVal());
        String powerState = virtualMachine.getRuntime().getPowerState().toString();

        if ("poweredOn".equals(powerState) && m_importVMPoweredOn) {
            return true;
        }
        if ("poweredOff".equals(powerState) && m_importVMPoweredOff) {
            return true;
        }
        if ("suspended".equals(powerState) && m_importVMSuspended) {
            return true;
        }

        return false;
    }

    /**
     * Iterates through the host systems and adds them to the requisition object.
     *
     * @param vmwareViJavaAccess the access/connection to use
     * @throws RemoteException
     */
    private void iterateHostSystems(VmwareViJavaAccess vmwareViJavaAccess, int apiVersion) throws RemoteException {
        ManagedEntity[] hostSystems;

        // search for host systems (esx hosts)
        logger.debug("Starting to iterate host systems on VMware host {} ...", m_hostname);
        hostSystems = vmwareViJavaAccess.searchManagedEntities("HostSystem");

        if (hostSystems != null) {

            for (ManagedEntity managedEntity : hostSystems) {
                HostSystem hostSystem = (HostSystem) managedEntity;
                logger.debug("Iterating host systems on VMware management server {} : {} (ID: {})", m_hostname,
                        hostSystem.getName(), hostSystem.getMOR().getVal());

                m_hostSystemMap.put(hostSystem.getMOR().getVal(), hostSystem.getName());

                // check for correct key/value-pair
                if (checkHostPowerState(hostSystem) && checkForAttribute(hostSystem)) {
                    logger.debug("Adding Host System '{}' (ID: {})", hostSystem.getName(),
                            hostSystem.getMOR().getVal());

                    // iterate over all service console networks and add interface Ip addresses
                    TreeSet<String> ipAddresses = vmwareViJavaAccess.getHostSystemIpAddresses(hostSystem);

                    // create the new node...
                    RequisitionNode node = createRequisitionNode(ipAddresses, hostSystem, apiVersion,
                            vmwareViJavaAccess);

                    // add cpu
                    try {
                        node.putAsset(new RequisitionAsset("cpu",
                                hostSystem.getHardware().getCpuInfo().getNumCpuCores() + " cores"));
                    } catch (Exception e) {
                        logger.debug("Can't find CPU information for {} (ID: {})", hostSystem.getName(),
                                hostSystem.getMOR().getVal());
                    }

                    // add memory
                    try {
                        node.putAsset(new RequisitionAsset("ram",
                                Math.round(hostSystem.getHardware().getMemorySize() / 1000000f) + " MB"));
                    } catch (Exception e) {
                        logger.debug("Can't find Memory information for {} (ID: {})", hostSystem.getName(),
                                hostSystem.getMOR().getVal());
                    }

                    // add vendor
                    /*
                    try {
                    node.putAsset(new RequisitionAsset("vendor", hostSystem.getHardware().getSystemInfo().getVendor()));
                    } catch (Exception e) {
                    logger.debug("Can't find vendor information for {}", hostSystem.getName());
                    }
                    */

                    // ...and add it to the requisition
                    if (node != null && m_persistHosts) {
                        m_requisition.insertNode(node);
                    }
                }
            }
        }
    }

    /**
     * Iterates through the virtual machines and adds them to the requisition object.
     *
     * @param vmwareViJavaAccess the access/connection to use
     * @throws RemoteException
     */
    private void iterateVirtualMachines(VmwareViJavaAccess vmwareViJavaAccess, int apiVersion)
            throws RemoteException {
        ManagedEntity[] virtualMachines;

        // search for all virtual machines
        virtualMachines = vmwareViJavaAccess.searchManagedEntities("VirtualMachine");

        if (virtualMachines != null) {

            // check for correct key/value-pair
            for (ManagedEntity managedEntity : virtualMachines) {
                VirtualMachine virtualMachine = (VirtualMachine) managedEntity;
                logger.debug("Iterating host systems on VMware management server {} : {} (ID: {})", m_hostname,
                        virtualMachine.getName(), virtualMachine.getMOR().getVal());

                // import only when the specified attributes is set
                if (checkVMPowerState(virtualMachine) && checkForAttribute(virtualMachine)) {
                    logger.debug("Adding Virtual Machine '{}' (ID: {})", virtualMachine.getName(),
                            virtualMachine.getMOR().getVal());

                    // iterate over all interfaces
                    TreeSet<String> ipAddresses = vmwareViJavaAccess.getVirtualMachineIpAddresses(virtualMachine);

                    // create the new node...
                    RequisitionNode node = createRequisitionNode(ipAddresses, virtualMachine, apiVersion,
                            vmwareViJavaAccess);

                    // add the operating system
                    if (virtualMachine.getGuest().getGuestFullName() != null) {
                        node.putAsset(new RequisitionAsset("operatingSystem",
                                virtualMachine.getGuest().getGuestFullName()));
                    }

                    // add cpu
                    try {
                        node.putAsset(new RequisitionAsset("cpu",
                                virtualMachine.getConfig().getHardware().getNumCPU() + " vCPU"));
                    } catch (Exception e) {
                        logger.debug("Can't find CPU information for {} (ID: {})", virtualMachine.getName(),
                                virtualMachine.getMOR().getVal());
                    }

                    // add memory
                    try {
                        node.putAsset(new RequisitionAsset("ram",
                                virtualMachine.getConfig().getHardware().getMemoryMB() + " MB"));
                    } catch (Exception e) {
                        logger.debug("Can't find Memory information for {} (ID: {})", virtualMachine.getName(),
                                virtualMachine.getMOR().getVal());
                    }

                    // ...and add it to the requisition
                    if (node != null && m_persistVMs) {
                        m_requisition.insertNode(node);
                    }
                }
            }
        }
    }

    /**
     * Checks whether an attribute/value is defined by a managed entity.
     * 
     * <p>The old implementation allows the user to specify only one parameter.</p>
     * <p>The new implementation allows the user to use a regular expression for the value:</p>
     * <ul><li>key=location&value=~North.*</li></ul>
     * <p>As an alternative, now it is possible to specify several parameters on the query.
     * The rule is to add an underscore character ('_') before the patameter's name and use similar rules for the value:</p>
     * <ul><li>_location=~North.*</li></ul>
     * <p>With the new parameter specification, it is possible to pass several attributes. The managed entity must match
     * all of them to be accepted.</p>
     * <p>The new specification will take precedence over the old specification. If the new specification is not being used,
     * the old one will be processed. Otherwise, the new one will be processed, and the old one will be ignored. There is no
     * way to use both at the same time.</p>
     *
     * @param managedEntity the managed entity to check
     * @return true if present and value is equal, false otherwise
     * @throws RemoteException
     */
    private boolean checkForAttribute(ManagedEntity managedEntity) throws RemoteException {
        logger.debug("Getting custom attributes from VMware management server {} : ManagedEntity {} (ID: {})",
                m_hostname, managedEntity.getName(), managedEntity.getMOR().getVal());
        Map<String, String> attribMap = getCustomAttributes(managedEntity);

        Set<String> keySet = new TreeSet<String>();
        for (String k : m_args.keySet()) {
            if (k.startsWith("_")) {
                keySet.add(k);
            }
        }

        if (!keySet.isEmpty()) {
            boolean ok = true;
            for (String keyName : keySet) {
                String attribValue = attribMap.get(StringUtils.removeStart(keyName, "_"));
                if (attribValue == null) {
                    ok = false;
                } else {
                    String keyValue = m_args.get(keyName);
                    if (keyValue.startsWith("~")) {
                        ok = ok && attribValue.matches(StringUtils.removeStart(keyValue, "~"));
                    } else {
                        ok = ok && attribValue.equals(keyValue);
                    }
                }
            }
            return ok;
        }

        String key = m_args.get("key");
        String value = m_args.get("value");

        // if key/value is not set, return true
        if (key == null && value == null) {
            return true;
        }

        // if only key or value is set, return false
        if (key == null || value == null) {
            return false;
        }

        // now search for the correct key/value pair
        String attribValue = attribMap.get(key);
        if (attribValue != null) {
            if (value.startsWith("~")) {
                return attribValue.matches(StringUtils.removeStart(value, "~"));
            } else {
                return attribValue.equals(value);
            }
        }

        return false;
    }

    /**
     * Gets the custom attributes.
     *
     * @param entity the entity
     * @return the custom attributes
     * @throws RemoteException the remote exception
     */
    private Map<String, String> getCustomAttributes(ManagedEntity entity) throws RemoteException {
        final Map<String, String> attributes = new TreeMap<String, String>();
        logger.debug("Getting custom attributes from VMware management server {} : ManagedEntity {} (ID: {})",
                m_hostname, entity.getName(), entity.getMOR().getVal());
        CustomFieldDef[] defs = entity.getAvailableField();
        CustomFieldValue[] values = entity.getCustomValue();
        for (int i = 0; defs != null && i < defs.length; i++) {
            String key = defs[i].getName();
            int targetIndex = defs[i].getKey();
            for (int j = 0; values != null && j < values.length; j++) {
                if (targetIndex == values[j].getKey()) {
                    attributes.put(key, ((CustomFieldStringValue) values[j]).getValue());
                }
            }
        }
        return attributes;
    }

    /**
     * {@inheritDoc}
     * <p/>
     * Creates a ByteArrayInputStream implementation of InputStream of the XML
     * marshaled version of the Requisition class. Calling close on this stream
     * is safe.
     */
    @Override
    public InputStream getInputStream() throws IOException {

        InputStream stream = null;

        try {
            logger.debug("Getting existing requisition (if any) for VMware management server {}", m_hostname);
            Requisition curReq = getExistingRequisition();
            logger.debug("Building new requisition for VMware management server {}", m_hostname);
            Requisition newReq = buildVMwareRequisition();
            logger.debug("Finished building new requisition for VMware management server {}", m_hostname);
            if (curReq == null) {
                if (newReq == null) {
                    // FIXME Is this correct ? This is the old behavior
                    newReq = new Requisition(m_foreignSource);
                }
            } else {
                if (newReq == null) {
                    // If there is a requisition and the vCenter is not responding for some reason, it is better to use the old requisition,
                    // instead of returning an empty one, which can cause the lost of all the nodes from the DB.
                    newReq = curReq;
                } else {
                    // If there is already a requisition, retrieve the custom assets and categories from the old one, and put them on the new one.
                    // The VMWare related assets and categories will be preserved.
                    for (RequisitionNode newNode : newReq.getNodes()) {
                        for (RequisitionNode curNode : curReq.getNodes()) {
                            if (newNode.getForeignId().equals(curNode.getForeignId())) {
                                // Add existing custom assets
                                for (RequisitionAsset asset : curNode.getAssets()) {
                                    if (!asset.getName().startsWith("vmware")) {
                                        newNode.putAsset(asset);
                                    }
                                }
                                // Add existing custom categories
                                for (RequisitionCategory cat : curNode.getCategories()) {
                                    if (!cat.getName().startsWith("VMWare")) {
                                        newNode.putCategory(cat);
                                    }
                                }
                                // Add existing custom services
                                /*
                                 * For each interface on the new requisition,
                                 * - Retrieve the list of custom services from the corresponding interface on the existing requisition,
                                 *   matching the interface by the IP address
                                 * - If the list of services is not empty, add them to the new interface
                                 */
                                for (RequisitionInterface intf : curNode.getInterfaces()) {
                                    List<RequisitionMonitoredService> services = getManualyConfiguredServices(intf);
                                    if (!services.isEmpty()) {
                                        RequisitionInterface newIntf = getRequisitionInterface(newNode,
                                                intf.getIpAddr());
                                        if (newIntf != null) {
                                            newIntf.getMonitoredServices().addAll(services);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            stream = new ByteArrayInputStream(jaxBMarshal(newReq).getBytes());
        } catch (Throwable e) {
            logger.warn("Problem getting input stream: '{}'", e);
            throw new IOExceptionWithCause("Problem getting input stream: " + e, e);
        }

        return stream;
    }

    protected Requisition getExistingRequisition() {
        Requisition curReq = null;
        try {
            ForeignSourceRepository repository = BeanUtils.getBean("daoContext", "deployedForeignSourceRepository",
                    ForeignSourceRepository.class);
            if (repository != null) {
                curReq = repository.getRequisition(m_foreignSource);
            }
        } catch (Exception e) {
            logger.warn("Can't retrieve requisition {}", m_foreignSource);
        }
        return curReq;
    }

    private RequisitionInterface getRequisitionInterface(RequisitionNode node, String ipAddr) {
        for (RequisitionInterface intf : node.getInterfaces()) {
            if (ipAddr.equals(intf.getIpAddr())) {
                return intf;
            }
        }
        return null;
    }

    private List<RequisitionMonitoredService> getManualyConfiguredServices(RequisitionInterface intf) {
        List<RequisitionMonitoredService> services = new ArrayList<RequisitionMonitoredService>();
        for (RequisitionMonitoredService svc : intf.getMonitoredServices()) {
            boolean found = false;
            for (String svcName : m_hostSystemServices) {
                if (svcName.trim().equals(svc.getServiceName())) {
                    found = true;
                    continue;
                }
            }
            for (String svcName : m_virtualMachineServices) {
                if (svcName.trim().equals(svc.getServiceName())) {
                    found = true;
                    continue;
                }
            }
            if (!found) {
                services.add(svc);
            }
        }
        return services;
    }

    /**
     * Utility to marshal the Requisition class into XML.
     *
     * @param r the requisition object
     * @return a String of XML encoding the Requisition class
     * @throws javax.xml.bind.JAXBException
     */
    private String jaxBMarshal(Requisition r) throws JAXBException {
        return JaxbUtils.marshal(r);
    }
}