net.emotivecloud.scheduler.drp4one.DRP4OVF.java Source code

Java tutorial

Introduction

Here is the source code for net.emotivecloud.scheduler.drp4one.DRP4OVF.java

Source

/**
 * Copyright (C) 2010-2013 Barcelona Supercomputing Center
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version. This library 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 Lesser
 * General Public License for more details. You should have received a copy of
 * the GNU Lesser General Public License along with this library; if not, write
 * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307 USA
 */
package net.emotivecloud.scheduler.drp4one;

import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.spi.resource.Singleton;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Scanner;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.xml.bind.JAXBException;
import javax.xml.bind.MarshalException;
import javax.xml.bind.PropertyException;
import javax.xml.bind.UnmarshalException;
import javax.xml.bind.ValidationException;
import javax.xml.parsers.ParserConfigurationException;
import net.emotivecloud.commons.ListStrings;
import net.emotivecloud.scheduler.drp4one.DRP4OVF.TargetedDisk;
import net.emotivecloud.utils.oca.OCAComplexComputeWrapper;
import net.emotivecloud.utils.oca.OCAComputeListWrapper;
import net.emotivecloud.utils.oca.OCAComputeListWrapperFactory;
import net.emotivecloud.utils.oca.OCAComputeWrapper;
import net.emotivecloud.utils.oca.OCAComputeWrapperFactory;
import net.emotivecloud.utils.oca.OCADiskWrapper;
import net.emotivecloud.utils.oca.OCANicWrapper;
import net.emotivecloud.utils.ovf.EmotiveOVF;
import net.emotivecloud.utils.ovf.EmotiveOVF.State;
import net.emotivecloud.utils.ovf.OVFAux;
import net.emotivecloud.utils.ovf.OVFDisk;
import net.emotivecloud.utils.ovf.OVFException;
import net.emotivecloud.utils.ovf.OVFNetwork;
import net.emotivecloud.utils.ovf.OVFWrapper;
import net.emotivecloud.utils.ovf.OVFWrapperFactory;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dmtf.schemas.ovf.envelope._1.ProductSectionType;
import org.dmtf.schemas.ovf.envelope._1.SectionType;
import org.opennebula.client.Client;
import org.opennebula.client.OneResponse;
import org.opennebula.client.vm.VirtualMachine;
import org.opennebula.client.vm.VirtualMachinePool;
import org.xml.sax.SAXException;

/**
 * *************************************************************************
 * Este es el componente con el cual la capa de Gestin de Cloud Federada *
 * interacta directamente. Se trata de un interfaz REST. La implementacin* que
 * se har ser mediante el protocolo HTTP y los mtodos GET, POST, PUT* y
 * DELETE. *
 *
 * ------------------------------------------------------------------------*
 * Skeleton reused by ENG with BSC fine OVFWrapper to use OpenNebula OCA *
 * ************************************************************************
 */
/**
 * This is the OCCI API interface with whom the VMManager interacts with
 * OpenNebula. It is an extension of the REST OCCI API, which transforms the
 * http requests to XML-RPC that OpenNebula can execute.
 *
 * REST Interface:
 *
 * @GET
 * @Path("/compute"):
 * @GET
 * @Path("/compute/{envid}"):
 * @GET
 * @Path("/compute/all"):
 * @GET
 * @Path("/environments/{envid}/status"):
 * @GET
 * @Path("/environments/{envid}/{taskid}"):
 *
 * @POST /compute:
 *
 * @DELETE
 * @Path("/compute/{envid}"):
 *
 * @author
 */
@Path("/")
@Singleton
/**
 * Class
 * <code>DRP4OVF</code> the class providing the REST service implementation
 *
 * @author <a href="mailto:saint@eng.it">Gian Uberto Lauri</a>
 * @version $Revision$
 */
public class DRP4OVF {

    private static final String PROPS_FILE_NAME = "/props_file";
    private static final String VM_BASEIMAGE = "VM.baseimage";
    private static final String NET_CONNECTION_NAMES = "net.connectionNames";
    private static final String[] NET_CONNECTION_PROPS = { "ip", "mac", "netmask", "gateway" };
    private static HashMap<String, HashMap<String, String>> PRODUCT_PROPS = new HashMap<String, HashMap<String, String>>();
    @Context
    UriInfo uriInfo;
    private Log log = LogFactory.getLog(DRP4OVF.class);
    public final static String Status = " ,Status Code ";
    //    private final static String PROPFILE = "ovf4one.properties";
    private final static String PROPFILE = "/ovf4one.properties";
    List<String> arg1 = new ArrayList<String>();
    List<String> arg2 = new ArrayList<String>();
    String netConnectNames = "";
    List<String> nicNames = new ArrayList<String>();
    boolean weGotKernel = false;
    boolean weGotBootloader = false;
    boolean weGotBoot = false;
    boolean weGotDisk = false;
    boolean weUseKVM = false;

    private OneExtraFuncs oneExtraFuncs;
    private String user;
    private String passwd;
    private String rpcserver;
    //Optimis: ONE Datastore info
    private String ONE_DATASTORE_NAME = "optimis";
    private int ONE_DATASTORE_ID = 100;

    /**
     * Creates a new instance of
     * <code>DRP4OVF</code> .
     *
     * Throws an error if the property file is missing the values required to
     * configure the retrieval of the Open Nebula access secret.
     */
    public DRP4OVF() {
        /**
         * comentado x smendoza 08/02/2013
         *
         * String className = ovf4oneProperties(OCACLIENT_CLASS, true);
         *
         * if (className == null) { throw new
         * OpenNebulaConfigurationError(OCACLIENT_CLASS + ": missing a value for
         * the property"); }
         *
         * ocaClientProviderURL = ovf4oneProperties(OCACLIENT_URL, false);
         *
         * if (ocaClientProviderURL == null) { throw new
         * OpenNebulaConfigurationError(OCACLIENT_URL + ": missing a value for
         * the property"); }
         *
         * ocaClientProviderQuery = ovf4oneProperties(OCACLIENT_QUERY, false);
         *
         * if (ocaClientProviderQuery == null) { throw new
         * OpenNebulaConfigurationError(OCACLIENT_QUERY + ": missing a value for
         * the property"); }
         *
         * try { clientProvider = (OCAClientProvider) Class.forName(className)
         * .newInstance(); } catch (InstantiationException e) { throw new
         * OpenNebulaConfigurationError( "\n.Bad OCAClientProvider " + className
         * + ", either missing nullary constructor or suitable for an
         * InstantiationError. Message: " + e.getMessage()); } catch
         * (IllegalAccessException e) { throw new OpenNebulaConfigurationError(
         * "\n.Bad OCAClientProvider, no permission to create the instance of :"
         * + className + ". Message: " + e.getMessage()); } catch
         * (ClassNotFoundException e) { throw new OpenNebulaConfigurationError(
         * "\n.Missing OCAClientProvider, " + className + " in the CLASSPATH.
         * Message: " + e.getMessage()); } catch (ClassCastException e) { throw
         * new OpenNebulaConfigurationError("\n.Bad OCAClientProvider, " +
         * className + " does not extend OCAClientProvvider. Message: " +
         * e.getMessage()); } productPropsFolder =
         * ovf4oneProperties(PRODUCT_PROPS_FOLDER, false); scriptlocation =
         * ovf4oneProperties(SCRIPT_LOCATION, false);
         *
         * sshClientUser = ovf4oneProperties(SSH_USER, false);
         *
         * if (sshClientUser == null) { throw new
         * OpenNebulaConfigurationError(SSH_USER + ": missing a value for the
         * property"); }
         *
         * sshClientPrivKeyPath = ovf4oneProperties(SSH_PRIV_KEY_PATH, false);
         *
         * if (sshClientPrivKeyPath == null) { throw new
         * OpenNebulaConfigurationError(SSH_PRIV_KEY_PATH + ": missing a value
         * for the property"); }
         *
         */
        // Defining the projectID against DRP will operate
        this.oneExtraFuncs = new OneExtraFuncs();

        PropertiesConfiguration configDRP4OST = ConfigManager
                .getPropertiesConfiguration(ConfigManager.DRP4OST_CONFIG_FILE);
        this.user = configDRP4OST.getString("opennebula.access.userid");
        this.passwd = configDRP4OST.getString("opennebula.access.passwd");
        this.rpcserver = configDRP4OST.getString("opennebula.access.rpcserver");
        this.ONE_DATASTORE_ID = configDRP4OST.getInt("opennebula.datastore.id");

        System.out.println("this.user=" + this.user);
        System.out.println("this.passwd=" + this.passwd);
        System.out.println("this.rpcserver=" + this.rpcserver);
        System.out.println("this.ONE_DATASTORE_ID=" + this.ONE_DATASTORE_ID);

    }

    private Properties props;
    private OCAClientProvider clientProvider;
    private String ocaClientProviderURL;
    private String ocaClientProviderQuery;
    private String sshClientUser;
    private String sshClientPrivKeyPath;
    private String scriptlocation;
    private String productPropsFolder;
    public final static String OCACLIENT_CLASS = "OCA.CLIENT.CLASS";
    public final static String OCACLIENT_URL = "OCA.CLIENT.URL";
    public final static String OCACLIENT_QUERY = "OCA.CLIENT.QUERY";
    public final static String SSH_USER = "ssh.user";
    public final static String SSH_PRIV_KEY_PATH = "ssh.priv.key.path";
    public final static String SCRIPT_LOCATION = "script.location";
    public final static String PRODUCT_PROPS_FOLDER = "product.properties.location";

    /*
     * ===============================================================
     * 
     * These constants describe the supported Product Properties We use Product
     * Properties to hold informations meaningful for Opennebula but not
     * supported by OVF
     */
    // Path to the kernel image - mostly unused if you don't use XEN
    public final static String KERNEL = "KERNEL";
    // Path to the initrd image - mostly unused if you don't use XEN
    public final static String INITRD = "INITRD";
    // Device to be mounted as root
    public final static String ROOT = "ROOT";
    // Extra arguments to boot the kernel
    public final static String KERNEL_CMD = "KERNEL_CMD";
    // Path to the bootloader executable - mostly unused if you don't use XEN
    public final static String BOOTLOADER = "BOOTLOADER";
    // Tyoe if the boot device, must be one of those in BootType enum
    public final static String BOOT = "BOOT";
    // Architecture to be emulated. We support i386 (default) and x86_64
    public final static String ARCH = "ARCH";
    public final static String I_386 = "i386";
    public final static String I_686 = "i686";
    public final static String X86_64 = "x86_64";
    // Hypervisor in use - we support KVM and XEN
    public final static String HYPERVISOR = "HYPERVISOR";
    public final static String ONE_XMLRPC = "ONE_XMLRPC";
    private final static String OS_subAttributes[] = new String[] { KERNEL, INITRD, ROOT, KERNEL_CMD, BOOTLOADER,
            BOOT };
    // Suffixes to build disk related properties.
    public final static String PROP_PATORURL = ".SOURCE";
    public final static String PROP_TYPE = ".TYPE";
    public final static String PROP_FORMAT = ".FORMAT";
    // This is property file only, nothing in the ovf.
    // Specifies a CLUSTER where deploy the VMS created with
    // ovf
    // Maybe we could replace this with a change in the
    // scheduler
    public final static String CLUSTER = "CLUSTER";
    // This is property file only, nothing in the ovf.
    // Holds the UsageTracker endpoint url
    public final static String USAGE_TRACKER_URL = "usage.tracker.url";
    public final static String INFRASTRUCTURE_ID = "infrastructure.id";
    // This is the protocol part for the pseudo URLs used to access
    // pre-registered images
    public final static String ONE_PROTOCOL = "ovf4one://";
    // check if absolute file path is provided for VM image
    public final static String FILE_PATH_SEPARATOR = "/";
    // The protocol part for the pseudo URLs has a fixed size,
    // compute it a compile/init tim.
    private final static int ONE_PROTOCOL_LEN = ONE_PROTOCOL.length();

    private HashMap<String, Integer> idVsOneId = new HashMap<String, Integer>();

    /*
     * ===============================================================
     * 
     * This enum models the supported types for the BOOT.
     */
    private enum BootType {

        hd("hd"), fd("fd"), cdrom("cdrom"), network("network");

        private BootType(String asString) {
            this.asString = asString;
        }

        private String asString;

        public String toString() {
            return asString;
        }

        public static boolean isValid(String toTest) {
            return hd.asString.equals(toTest) || fd.asString.equals(toTest) || cdrom.asString.equals(toTest)
                    || network.asString.equals(toTest);
        }
    }

    /*
     * ===============================================================
     * 
     * This enum models the supported types for the DISK. We consider virtual
     * CD, floppies and such all being 'disks'
     */
    private enum DskType {

        virtualDisk("disk"), virtualSwap("swap"), blockDevice("block"), onTheFlyDisk("fs");
        private String asString;

        private DskType(String asString) {
            this.asString = asString;
        }

        public String toString() {
            return asString;
        }

        public static DskType fromString(String startingString) {
            return virtualDisk.asString.equals(startingString) ? virtualDisk
                    : virtualSwap.asString.equals(startingString) ? virtualSwap
                            : blockDevice.asString.equals(startingString) ? blockDevice
                                    : onTheFlyDisk.asString.equals(startingString) ? onTheFlyDisk : null;
        }
    }

    /**
     * *************************************************************************
     * Methods without a correspondence in the OCCI interface. *
     * ************************************************************************
     */
    @GET
    @Path("/info")
    @Produces("text/plain")
    /**
     * <code>info</code> a methods that simply tells that DRP4OVF is up and
     * ready
     *
     * @return a <code>String</code> The message stating that DRP4OVF is ready
     */
    public String info() {

        return "DRP is running";
    }
    //
    //    @GET
    //    @Path("/")
    //    @Produces("application/xml")
    //    /**
    //     * <code>rootMethod</code> Implementation for the default root method.
    //     * Returns an OCA format XML for all the user VMsm, the same of
    //     * getAllEnvironments()
    //     *
    //     * @param request an <code>HttpServletRequest</code> with the full http
    //     * request
    //     * @return a <code>String</code> the OCA format XML for all the user VMs
    //     */
    //    public String rootMethod(@Context HttpServletRequest request) {
    //        return getAllEnvironments(request);
    //    }
    //
    //    @GET
    //    @Path("/environments")
    //    @Produces("application/xml")
    //    /**
    //     * <code>getAllEnvironments</code> Non OCCI standard method. Returns an OCA
    //     * format XML for all the user VMs
    //     *
    //     * @param request an <code>HttpServletRequest</code> with the full http
    //     * request
    //     *
    //     * @return a <code>String</code> the OCA format XML for all the user VMs
    //     */
    //    public String getAllEnvironments(@Context HttpServletRequest request) {
    //
    //        Client ocaClient = getClient(request);
    //
    //        VirtualMachinePool vmpool = null;
    //
    //        try {
    //            vmpool = new VirtualMachinePool(ocaClient);
    //
    //        } catch (DRPOneException e) {
    //            throw new DRPOneException(
    //                    "Failed getAllEnviroments method!!"
    //                    + " An error occurred in the configuration of virtual machine pool."
    //                    + "\n Please, control your opennebula configuration ...."
    //                    + "variable vmpool is " + e.getCause() + ".\n",
    //                    StatusCodes.BAD_REQUEST);
    //
    //        }
    //        // OneResponse rc = VirtualMachinePool.info(ocaClient, 0);
    //        OneResponse rc = vmpool.info();
    //        if (rc.isError()) {
    //            log.error("Failed to retrieve VMs for user : "
    //                    + rc.getErrorMessage() + ".\n");
    //            throw new DRPOneException("Failed getAllEnviroments method!!"
    //                    + "Failed to retrieve all enviroments for user : "
    //                    + rc.getErrorMessage() + ".\n", StatusCodes.ONE_FAILURE);
    //        }
    //        /*
    //         * if(rc.isError()) { log.error("Failed to retrieve VMs for user : " +
    //         * rc.getErrorMessage()); throw new
    //         * DRPOneException("Failed to retrieve VMs for user : " +
    //         * rc.getErrorMessage(),StatusCodes.ONE_FAILURE); }
    //         */
    //
    //        return rc.getMessage();
    //
    //    }
    //
    //    @POST
    //    @Path("/environments/{envid}")
    //    /**
    //     * <code>submitActivity</code> Basically, it executes a command in the
    //     * machine that is specified as "envid". This is by no means OCCI code but a
    //     * BSC specific feature addet do have more interoperability.
    //     *
    //     * The task is specified as a Job Submission Description Language (JSDL) XML
    //     * file. I attach you a jar file that contains a parser for it.
    //     *
    //     * Use JSCH ( http://www.jcraft.com/jsch/), to transfer files by SCP to the
    //     * VM, and to start SSH command sessions for calling them.
    //     *
    //     * @param envid a <code>String</code> id of the vm you want to use for data
    //     * transfer/code execution
    //     * @param user a <code>String</code> id of the user on the vm you want to
    //     * use for data transfer/code execution
    //     * @param back a <code>String</code> flag. if the string contains "false"
    //     * (case sensitive), the command is run synchronously. Some remnant of BSC
    //     * having a grid ?
    //     * @param jsdl a <code>String</code> Description of the command to execute
    //     * @return a <code>String</code> the pid of the command
    //     */
    //    public String submitActivity(@PathParam("envid") String envId,
    //            @QueryParam("user") String user,
    //            @QueryParam("background") String back,
    //            @QueryParam("jsdl") String jsdl, @Context HttpServletRequest request)
    //            throws DRPOneException {
    //
    //        /*
    //         * First of all, get the VM description from ONE and find where it does
    //         * answer on port 22
    //         */
    //
    //        OneResponse rc = getComputeHelper(envId, request);
    //
    //        OCAComputeWrapper oca = rc2OCA(rc);
    //
    //        String userToUse = (user == null || "".equals(user.trim())) ? sshClientUser
    //                : user;
    //
    //        Collection<OCANicWrapper> nicList = oca.getTemplate().getNics()
    //                .values();
    //
    //        if (!(oca.getState() == VmStatusCodes.ACTIVE && oca.getLcmState() == LcmStatusCodes.RUNNING)) {
    //            throw new DRPOneException("\nFailed getCompute method!!\n"
    //                    + "VM id " + envId + " not ready to accept commands.\n .",
    //                    StatusCodes.VM_NOT_READY);
    //        }
    //
    //        String ipAddress = null;
    //        for (OCANicWrapper nic : nicList) {
    //            ipAddress = nic.getIp();
    //            if (ipAddress != null) {
    //                if (port22Reached(ipAddress)) {
    //                    break;
    //                }
    //            }
    //
    //        }
    //
    //        String rv = "";
    //        if (ipAddress == null) {
    //            throw new DRPOneException("\nFailed getCompute method!!\n"
    //                    + "VM id " + envId + " not responding on port 22.\n .",
    //                    StatusCodes.VM_NOT_RESPONDING);
    //        }
    //
    //        // We have the IP the machine has something listening on port 22
    //        /*
    //         * comentado x smendoza 08/02/2013
    //         * 
    //        if (!jsdl.startsWith("<?xml")) { // Ci possono passare il
    //            // comando oppure un JSDL, nel
    //            // qual caso comincia con <?xml
    //            // e noi facciamo il simpatico
    //            // parsing.
    //            JSDL jsdlaux = new JSDL();
    //            jsdlaux.setCommand(jsdl);
    //
    //            jsdl = jsdlaux.toString();
    //
    //            SSH ssh = new SSH(userToUse, sshClientPrivKeyPath, ipAddress);
    //            ssh.deploy();
    //            rv = ssh.execute(jsdlaux);
    //        }
    //        */
    //        // System.out.println("--Final Command--"+jsdl+"----");
    //
    //        return rv;
    //    }

    /**
     * *************************************************************************
     * Methods with a correspondence in the OCCI interface. *
     * ************************************************************************
     */
    @POST
    @Path("/compute")
    @Consumes("application/xml")
    @Produces("application/xml")
    /**
     * Method that managers the post to http://host/ovf4one/compute. This
     * creates a vm instance
     *
     * @param ovfXml a <code>String</code> an OVF file with the informations
     * that drive the VM instance creation
     * @param request an <code>HttpServletRequest</code> with the full http
     * request
     * @return a <code>String</code> an OVF input with the VM instance ID
     * @exception DRPOneException If something goes wrong, what else ?
     */
    public String createCompute(String ovfXml, @Context HttpServletRequest request)
            throws DRPOneException, ParserConfigurationException, SAXException { // (Map<String,
        // Object>);
        HashMap<String, String> hmap = new HashMap<String, String>();

        log.debug("entering create compute...");

        if (ovfXml == null) {
            throw new DRPOneException("\nFailed createCompute method!!\n." + "\nThe ovf xml is" + ovfXml
                    + "\n.Please enter correct xml ovf and try again.\n", StatusCodes.BAD_OVF);
        }
        log.debug("ovfxml is not null...");
        OVFWrapper ovf;

        try {
            log.debug("parsing the ovfxml...");
            ovf = parse(ovfXml);
            log.debug("parsing successful");
        } catch (DRPOneException e) {
            // This one is expectet to be thrown, and should
            // pass unchanged
            throw e;
        } catch (Exception e) {
            throw new DRPOneException("\nFailed createCompute method!!\n"
                    + "An error occured to parse ovfXml.\n The parse of ovfxml is " + e.getCause()
                    + "\n.Please enter correct xml ovf anf try again.\n", StatusCodes.BAD_OVF);

        }
        log.debug("parsed ovf:\n" + ovf);

        EmotiveOVF emotiveOvf = new EmotiveOVF(ovf);
        List<SectionType> sections = OVFAux.findSections(emotiveOvf.getOVFEnvelope().getSection(),
                ProductSectionType.class);
        ProductSectionType ps = null;
        for (SectionType s : sections) {
            if (s instanceof ProductSectionType
                    && ((ProductSectionType) s).getClazz().equals(OVFWrapper.class.getName())) {
                ps = (ProductSectionType) s;
                break;
            }
        }
        if (ps != null) {
            List cop = ps.getCategoryOrProperty();
            ProductSectionType.Property propertyToRemove = null;
            for (Object prop : cop) {
                if (prop instanceof ProductSectionType.Property) {
                    ProductSectionType.Property p = (ProductSectionType.Property) prop;
                    hmap.put(p.getKey(), p.getValueAttribute());
                    log.debug(p.getKey() + " " + p.getValueAttribute());
                }
            }
        }
        Client ocaClient = getClient(request);

        log.debug("created ocaclient");

        //1) Create the Images that will be used at the VM template
        System.out.println("DRP4ONE - createVM> Voy a llamar a oneExtraFuncs.createAllImages()...");
        oneExtraFuncs.createAllImages(getClient(request), ONE_DATASTORE_ID, ovf.getDisks().values(),
                emotiveOvf.getBaseImage());

        //2) Start creating the VM Template
        String vmTemplate = "";

        try {
            System.out.println("DRP4ONE - createVM> emotiveOvf:" + emotiveOvf);
            //            vmTemplate = ovf2OneDescription(emotiveOvf, request);
            vmTemplate = oneExtraFuncs.VMTemplate(ocaClient, emotiveOvf);
            //Sergio is doing a replace for the adequate ONE Network
            //            vmTemplate = vmTemplate.replace("NETWORK = \"public\" ", "NETWORK = \"" + myOneNet + "\"");
            System.out.println("***************************************************************");
            System.out.println("DRP4ONE - createVM> vmTemplate2 (REPLACED):" + vmTemplate);
            System.out.println("***************************************************************");
        } catch (Exception e) {
            log.error("Exception occurred:" + e.getMessage());
            System.out.println("DRP4ONE - createVM> EXPCECION SALTADA CREANDO TEMPLATE");
        }

        log.debug("vmtemplate:\n" + vmTemplate);
        // Creates the VM, keeping it at PENDING state (necessary to call deploy())
        System.out.println("DRP4ONE - createVM> allocating the VM");

        OneResponse rc = VirtualMachine.allocate(ocaClient, vmTemplate);

        if (rc.isError()) {
            System.out.println("DRP4ONE - createVM> ERROR while allocating the VM");
            System.out.println("DRP4ONE - createVM> Message: " + rc.getErrorMessage());
            throw new DRPOneException(
                    "\nFailed createCompute method!!\n" + "Failed to create VM " + rc.getErrorMessage() + Status,
                    StatusCodes.ONE_FAILURE);
        }
        int newVMID = Integer.parseInt(rc.getMessage());

        System.out.println("DRP4ONE - createVM> the new VM has newVMID=" + newVMID);

        // After created the VM, it is necessary to deploy the VM
        VirtualMachine myvm = new VirtualMachine(newVMID, ocaClient);
        String strHostName = emotiveOvf.getProductProperty(EmotiveOVF.PROPERTYNAME_DESTINATION_HOST);

        System.out.println("DRP4ONE - createVM> the VM host (extracted from OVF, strHostID=" + strHostName);

        //TODO: call the image creation
        // get the path
        //        String imgName = emotiveOvf.getBaseImage();
        //        String imgPath = imgsHome + "/" + imgName;
        //        System.out.println("DRP4ONE - createVM> imgName:" + imgName);
        //        System.out.println("DRP4ONE - createVM> imgPath:" + imgPath);
        // get the name
        //        oneExtraFuncs.createImage(ocaClient, ONE_DATASTORE_ID, imgName, imgPath);

        // this function gets id from a host name from OpenStack
        int hid = oneExtraFuncs.getIdFromName(getClient(request), strHostName);

        System.out.println("DRP4ONE  - oneExtraFuncs.getIdFromName(c," + strHostName + ")> : " + hid);

        //        int hostID = Integer.parseInt(hid);
        OneResponse rc_info = myvm.info();

        System.out.println("DRP4ONE  - createVM> rc_info: " + rc_info);

        //TODO: Use the host got from the ovf (now static "2")
        //Initiates the instance of the VM on the target host.
        //        OneResponse rc_deploy = myvm.deploy(hostID);
        System.out.println("B========================================D DRP4ONE  - myvm.deploy(" + hid + ")> : ");
        OneResponse rc_deploy = myvm.deploy(hid);

        if (rc_deploy.isError()) {
            System.out.println("DRP4ONE - createVM> ERROR while deploying the VM");
            throw new DRPOneException("\nFailed createCompute method!!\n" + "Failed to create VM "
                    + rc_deploy.getErrorMessage() + Status, StatusCodes.ONE_FAILURE);
        }

        System.out.println(
                "DRP4ONE - createVM> deploying VM at specific host, message from ONE: " + rc_deploy.getMessage());

        // The response message is the new VM's ID
        log.info("ok, ID " + newVMID + ".");

        OVFNetwork nets[] = this.getNetworks(request, newVMID);
        /*
         * notifyUsageTracker(newVMID, SecureSessionInfo.getUserDN(request));
         * log.info("UsageTracker notified for " + newVMID + ".");
         */
        // We can create a representation for the new VM, using the returned
        // VM-ID
        // Returning created domain.
        // get the disk section properties
        Collection<OVFDisk> tmpDisks = ovf.getDisks().values();
        OVFDisk disks[] = tmpDisks.toArray(new OVFDisk[tmpDisks.size()]);

        // get the network properties
        //        Collection<OVFNetwork> tmpNets = ovf.getNetworks().values();
        //        OVFNetwork nets[] = tmpNets.toArray(new OVFNetwork[tmpNets.size()]);
        // get the product properties
        // HashMap<String, String> hmap = new HashMap<String,String>();
        // SectionType product =
        // OVFAux.findSection(ovf.getOVFEnvelope().getSection(),
        // ProductSectionType.class);
        log.debug("RAM:" + ovf.getMemoryMB());

        String xx = OVFWrapperFactory.create(ovf.getId(), ovf.getCPUsNumber(), ovf.getMemoryMB(), disks, nets, hmap)
                .toCleanString();

        idVsOneId.put(ovf.getId(), newVMID);

        try {
            //Truco Josep pa guardar name 
            EmotiveOVF ovfDomEmo = new EmotiveOVF(xx);
            ovfDomEmo.setProductProperty(EmotiveOVF.PROPERTYNAME_VM_NAME, String.valueOf(newVMID));
        } catch (Exception e) {
            System.out.println("");
            e.printStackTrace();
        }

        if (!hmap.isEmpty()) {
            PRODUCT_PROPS.put(String.valueOf(newVMID), hmap);

            //            writeToFile(productPropsFolder + PROPS_FILE_NAME, String.valueOf(newVMID));
        }

        log.debug("ovf returned:" + xx);
        return xx;
    }

    @POST
    @Path("/compute/{vmId}/migrate")
    @Produces("application/xml")
    public String migrate(@PathParam("vmId") String vmId, @QueryParam("dstHost") String dstHost,
            @Context HttpServletRequest request) {
        //
        //    @POST
        //    @Path("/migrate/{envid}/{dstHost}")
        //    @Consumes("application/xml")
        //    @Produces("application/xml")
        //    public String migrate(@PathParam("envid") String strVMID, @PathParam("dstHost") String strDstHost,@Context HttpServletRequest request) {
        Client ocaClient = getClient(request);
        // After created the VM, it is necessary to deploy the VM
        int fromID = Integer.parseInt(vmId);
        VirtualMachine myvm = new VirtualMachine(fromID, ocaClient);
        //        int hostID = Integer.parseInt(strHostName);
        OneResponse rc_info = myvm.info();
        int toID = Integer.parseInt(dstHost);
        OneResponse rc_deploy = myvm.deploy(toID);

        //        String xx = OVFWrapperFactory.create(String.valueOf(newVMID),
        //                ovf.getCPUsNumber(), ovf.getMemoryMB(), disks, nets, hmap)
        //                .toCleanString();

        return null;
    }

    private void writeToFile(String fileName, String vmId) {
        try {

            HashMap<String, String> hmap = PRODUCT_PROPS.get(vmId);

            Iterator<String> hmapIter = hmap.keySet().iterator();
            new File(productPropsFolder + PROPS_FILE_NAME).createNewFile();

            PropertiesConfiguration props_config = new PropertiesConfiguration(
                    new File(productPropsFolder + PROPS_FILE_NAME));
            props_config.addProperty(vmId, hmap);
            log.debug("saving to properties file..");
            props_config.save();

        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @GET
    @Path("/compute/{envid}")
    @Produces("application/xml")
    /**
     * Method to manage the get to http://host/ovf4one/compute/[envid], that
     * retrieves data about the given VM instance
     *
     * @param envId a <code>String</code> the ID of the VM instance we are
     * interested in
     * @param request an <code>HttpServletRequest</code> with the full http
     * request
     * @return a <code>String</code> an OVF file with the required informations
     * @exception DRPOneException If something goes wrong, what else ?
     *
     */
    public String getCompute(@PathParam("envid") String envId, @Context HttpServletRequest request)
            throws DRPOneException {

        String oneID = String.valueOf(idVsOneId.get(envId));

        OneResponse rc = getComputeHelper(envId, request);

        OCAComputeWrapper oca = rc2OCA(rc);

        Collection<OCADiskWrapper> diskList = oca.getTemplate().getDisks().values();

        OVFDisk diskArray[] = new OVFDisk[diskList.size()];

        int counter = 0;

        for (OCADiskWrapper disk : diskList) {
            String diskId = disk.getDiskId();
            diskArray[counter++] = new OVFDisk((diskId == null) ? "AnonDisk_" + counter : diskId, disk.getSource(),
                    disk.getSize());
        }

        Collection<OCANicWrapper> nicList = oca.getTemplate().getNics().values();

        OVFNetwork nicArray[] = new OVFNetwork[nicList.size()];

        counter = 0;
        int vmStatus = oca.getState();
        int lcmState = oca.getLcmState();
        boolean doThePoll = vmStatus == VmStatusCodes.ACTIVE && lcmState == LcmStatusCodes.RUNNING;

        boolean gotPort22Connection = false;

        for (OCANicWrapper nic : nicList) {
            String netName = nic.getNetwork();
            String ipAddress = nic.getIp();

            nicArray[counter++] = new OVFNetwork((netName == null) ? "AnonNet_" + counter : netName, ipAddress,
                    nic.getMac());
            if (doThePoll && ipAddress != null) {
                gotPort22Connection |= port22Reached(ipAddress);
            }

        }

        HashMap<String, String> props_hmap = getPropsFromFile(productPropsFolder + PROPS_FILE_NAME,
                String.valueOf(oca.getId()));

        EmotiveOVF ovfReply = OVFWrapperFactory.create("" + oca.getId(), oca.getCpu(), oca.getMemory(), diskArray,
                nicArray, props_hmap);

        ovfReply.setState(one2libvrtStatus(vmStatus, lcmState, gotPort22Connection));

        String rv = ovfReply.toCleanString();
        return rv;
    }

    private OneResponse getComputeHelper(String envId, HttpServletRequest request) throws DRPOneException {
        Client ocaClient = getClient(request);

        int machineId = 0;

        try {
            machineId = Integer.parseInt(envId);
        } catch (NumberFormatException nfe) {
            throw new DRPOneException("\nFailed getCompute method!!\n" + "Illegal VM id " + envId
                    + ".\n Please enter correct VM id and try again.", StatusCodes.VM_NOT_EXIST);
        }

        OneResponse rc = VirtualMachine.info(ocaClient, machineId);

        log.debug("This is the information OpenNebula stores for the new VM:" + rc.getMessage() + "\n");

        if (rc.isError()) {
            throw new DRPOneException("Failed getCompute method!!\n" + " Failed to retrieve VM with ID " + envId
                    + " : " + rc.getErrorMessage(), StatusCodes.ONE_FAILURE);
        }

        return rc;

    }

    private OCAComputeWrapper rc2OCA(OneResponse rc) {
        String tmp = rc.getMessage();
        StringBuilder xmlReply = new StringBuilder(64 + tmp.length());
        xmlReply.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
        xmlReply.append(tmp);

        return parseOcaCompute(xmlReply.toString());
    }

    /**
     *
     * @return A ListStrings object containing the vmIDs of the domains running
     * in the system.
     */
    @GET
    @Path("/compute")
    @Produces("application/xml")
    public ListStrings getComputes(@Context HttpServletRequest req) {
        ListStrings ret = new ListStrings();

        OCAComputeListWrapper oca = getComputesHelper(req);

        for (OCAComplexComputeWrapper complexCompute : oca) {
            //            String id = String.valueOf(complexCompute.getId());
            Integer id = oneExtraFuncs.getKeyOfValue(this.idVsOneId, complexCompute.getId());
            ret.add("" + id);
        }
        return ret;

    }

    @GET
    @Path("/compute/all")
    @Produces("application/xml")
    /**
     * <code>getComputesAll</code> Returns an XML with the ID of all the user
     * VMs
     *
     * @param request an <code>HttpServletRequest</code> with the full http
     * request
     * @return a <code>ListStrings</code> the list of the VMs
     */
    public ListStrings getComputesAll(@Context HttpServletRequest request) {
        ListStrings ret = new ListStrings();
        log.debug("entered computeall method");

        OCAComputeListWrapper oca = getComputesHelper(request);

        for (OCAComplexComputeWrapper complexCompute : oca) {
            Map<String, OCADiskWrapper> disks = complexCompute.getTemplate().getDisks();

            OVFDisk ovfDisks[] = new OVFDisk[disks.size()];

            int counter = 0;
            for (OCADiskWrapper disk : disks.values()) {
                String diskId = disk.getDiskId();

                ovfDisks[counter++] = new OVFDisk(((diskId == null) ? "AnonDisk_" + counter : diskId),
                        disk.getSource(), disk.getSize());
            }

            Map<String, OCANicWrapper> nics = complexCompute.getTemplate().getNics();
            OVFNetwork ovfNics[] = new OVFNetwork[nics.size()];
            counter = 0;

            int vmStatus = complexCompute.getState();
            int lcmState = complexCompute.getLcmState();
            boolean doThePoll = vmStatus == VmStatusCodes.ACTIVE && lcmState == LcmStatusCodes.RUNNING;

            boolean gotPort22Connection = false;

            for (OCANicWrapper nic : nics.values()) {
                String netName = nic.getNetwork();
                String ipAddress = nic.getIp();

                ovfNics[counter++] = new OVFNetwork((netName == null) ? "AnonNet_" + counter : netName, ipAddress,
                        nic.getMac());
                if (doThePoll && ipAddress != null) {
                    gotPort22Connection |= port22Reached(ipAddress);
                }

            }

            HashMap<String, String> props_hmap = getPropsFromFile(productPropsFolder + PROPS_FILE_NAME,
                    String.valueOf(complexCompute.getId()));

            EmotiveOVF tmpOvf = OVFWrapperFactory.create(complexCompute.getId() + "",
                    complexCompute.getTemplate().getCpu(), complexCompute.getMemory(), ovfDisks, ovfNics,
                    props_hmap);
            tmpOvf.setState(one2libvrtStatus(vmStatus, lcmState, gotPort22Connection));

            tmpOvf.setProductProperty(EmotiveOVF.PROPERTYNAME_VM_NAME, complexCompute.getName());

            ret.add(tmpOvf.toCleanString());
        }

        return ret;
    }

    private HashMap<String, String> getPropsFromFile(String fileName, String vmId) {
        Object product_propsList = "";
        HashMap<String, String> hmap = new HashMap<String, String>();
        String[] product_props = {};
        try {
            PropertiesConfiguration props_config = new PropertiesConfiguration(new File(fileName));

            if (props_config.containsKey(vmId)) {
                log.debug("getting the product properties for vm: " + vmId);
                product_propsList = props_config.getProperty(vmId);
                if (product_propsList.toString().contains(",")) {
                    product_props = product_propsList.toString()
                            .substring(1, product_propsList.toString().length() - 1).split(",");

                    for (String product_prop : product_props) {
                        if (product_prop.contains("=")) {
                            String[] product_property = product_prop.split("=");
                            hmap.put(product_property[0], product_property[1]);
                            log.debug("adding product property " + product_property[0] + " " + product_property[1]);
                        }
                    }
                } else {
                    String[] product_property = product_propsList.toString()
                            .substring(1, product_propsList.toString().length() - 1).split("=");
                    if (product_property.length == 2) {
                        hmap.put(product_property[0], product_property[1]);
                        log.debug("adding product property " + product_property[0] + " " + product_property[1]);
                    } else {
                        log.error("error in the product property, does nt contain a valid key value pair..");
                    }

                }

            } else {
                log.debug("no such key exists " + vmId);
            }

        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return hmap;
    }

    private OCAComputeListWrapper getComputesHelper(HttpServletRequest request) {
        Client ocaClient = getClient(request);

        OneResponse rc = VirtualMachinePool.info(ocaClient, -1);

        if (rc.isError()) {
            throw new DRPOneException(
                    "\nFailed getComputesAll method!!\n." + "An error occured in the virtual machine "
                            + "configuration pool. vmpool is " + rc.getMessage() + "\nPlease try again\n.",
                    StatusCodes.VM_NOT_EXIST);
        }

        String tmp = rc.getMessage();
        StringBuilder xmlReply = new StringBuilder(64 + tmp.length());
        xmlReply.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
        xmlReply.append(tmp);

        return parseOcaComputeList(xmlReply.toString());
    }

    @DELETE
    @Path("/compute/{envid}")
    /**
     * <code>deleteCompute</code> Kills an instance of a VM
     *
     * @param envid a <code>String</code> the id of the VM to kill
     * @param request an <code>HttpServletRequest</code> with the full http
     * request
     * @exception DRPOneException when something goes wrong.
     */
    public void deleteCompute(@PathParam("envid") String envid, @Context HttpServletRequest request)
            throws DRPOneException {

        Client ocaClient = getClient(request);

        int machineId = -1;
        int oneID = -1;
        try {
            //            machineId = Integer.parseInt(envid);
            if (idVsOneId.containsKey(envid)) {
                oneID = idVsOneId.get(envid);
            } else {
                machineId = Integer.parseInt(envid);
            }
            System.out.println("DRP4ONE:deleteCompute()> idVsOneId.get(envid)=" + oneID);

        } catch (NumberFormatException nfe) {
            throw new DRPOneException(
                    "\nFailed deleteCompute method!!\n" + "Illegal machine ID, it is " + machineId
                            + ".\nPlease enter correct machine id and try again." + Status,
                    StatusCodes.BAD_REQUEST);
        }

        VirtualMachine vm = new VirtualMachine(oneID, ocaClient);

        OneResponse rc = vm.finalizeVM();
        // return a message as "wait please..."
        System.out.println("\n... Trying to finalize (delete) the VM ...." + envid + "...");
        if (rc.isError()) {
            // log.error("Failed to delete vm instance " + envid +": " +
            // rc.getErrorMessage());
            throw new DRPOneException("\nFailed deleteCompute method!!" + "The enviroments " + envid
                    + "is not correct.Please enter correct Id enviroment and try again...\n. The Virtual Machine Error Message is "
                    + rc.getErrorMessage(), StatusCodes.ONE_FAILURE);
        }

        log.info("Environment " + envid + " was destroyed.");
    }

    /*
     * ==============================================================
     * ==============================================================
     * 
     * private helpers for the createCompute method
     */
    private OVFWrapper parse(String ovfXml) throws DRPOneException {
        OVFWrapper rv = null;
        StringBuilder cause = new StringBuilder();

        try {
            rv = OVFWrapperFactory.parse(ovfXml);
        } catch (JAXBException e) {
            if (e instanceof PropertyException) {
                cause.append("Access to property failed: " + e.getErrorCode());
            } else if (e instanceof MarshalException) {
                cause.append("Marshalling failed: " + e.getLocalizedMessage());
            } else if (e instanceof UnmarshalException) {
                cause.append("Unmarshalling failed: " + e.getCause());
            } else if (e instanceof ValidationException) {
                cause.append("XML Validation failed: " + e.getErrorCode());
            } else {
                cause.append("Unespected " + e.getErrorCode());
                cause.append(e.getClass().getName());
                cause.append(": ");
            }

            cause.append(e.getMessage());
            log.error(cause.toString());
            if (log.isTraceEnabled()) {
                log.trace(cause, e);
            }
            throw new DRPOneException(cause.toString(), e, StatusCodes.XML_PROBLEM);
        } catch (OVFException e) {
            cause.append("Problems parsing OVF file: ");
            cause.append(e.getMessage());
            log.error(cause.toString());
            if (log.isTraceEnabled()) {
                log.trace(cause, e);
            }
            throw new DRPOneException(cause.toString(), e, StatusCodes.XML_PROBLEM);
        }
        return rv;
    }

    private boolean isKVMInUse(EmotiveOVF ovf) {

        // TODO: CLEAR THIS CODE!!!
        // String hyperName = ovf.getProductProperty(HYPERVISOR);

        String hyperName = ovf.getProductProperty(HYPERVISOR);
        String propHyperName = null;
        propHyperName = ovf4oneProperties(HYPERVISOR, false);
        hyperName = hyperName == null ? propHyperName : hyperName;
        return hyperName == null || "kvm".equalsIgnoreCase(hyperName);
    }

    // Generates a VM description starting from an ovf wrapper.
    private String ovf2OneDescription(EmotiveOVF ovf, HttpServletRequest request) throws IOException {
        StringBuilder buf = new StringBuilder(1024);
        String netConnectNames = "";
        // Name, CPUs and Memory
        // they are not mandatory , a name is generated by one will be
        // one_<VID> form
        //        boolean weUseKVM = isKVMInUse(ovf);

        //    These are flags to check if a certain mandatory [*] values are
        //    supplied with the OVF.
        //
        //    [*] some values are mandatory with XEN, other with KVM...
        //    See at http://opennebula.org/documentation:archives:rel2.0:template

        List<String> device_map = Arrays.asList("vdb", "vdc", "vdd", "vde");
        int no_of_virtual_disk = 0;
        Object tmp = ovf.getId();
        if (tmp != null) {
            buf.append("NAME = \"");
            buf.append(tmp);
            buf.append("\"\n");
        }

        tmp = ovf.getMemoryMB();
        if (tmp != null) {
            buf.append("MEMORY = ");
            buf.append(tmp);
            buf.append("\n");
        } // @madigiro - 20th july
        else if ((tmp = ovf4oneProperties("MEMORY", false)) != null) {
            buf.append("MEMORY = ");
            buf.append(tmp);
            buf.append("\n");
        } else {
            throw new DRPOneException("OVF file is missing mandatory " + "memory specification.\n Please,",
                    StatusCodes.NOT_ACCEPTABLE);
        }

        tmp = ovf.getCPUsNumber();
        if (tmp != null) {
            // It seems that in our OVF VCPUs and CPUs are the same thing.
            buf.append("CPU = ");
            buf.append(tmp);
            buf.append("\n");
            buf.append("VCPU = ");
            buf.append(tmp);
            buf.append("\n");
        } else if ((tmp = ovf4oneProperties("CPU", false)) != null) {
            buf.append("CPU = ");
            buf.append(tmp);
            buf.append("\n");
            buf.append("VCPU = ");
            buf.append(tmp);
            buf.append("\n");
            // throw new
            // DRPOneException("OVF file is missing mandatory CPU number specification ",StatusCodes.BAD_OVF);
        } else {
            throw new DRPOneException("OVF file is missing mandatory " + "CPU specification.\n",
                    StatusCodes.NOT_ACCEPTABLE);
        }

        // Get the OS section
        String os = VMDescriptionOS(ovf);
        buf.append(os);

        // Get the DISK's section
        //        String d = VMDescriptionDisks(ovf);
        String d = oneExtraFuncs.VMDescriptionDisks(getClient(request), ovf.getDisks().values());
        buf.append(d);

        try {
            log.debug("genereated init.sh:");
            // bw.close();
        } catch (Exception e) {
            log.error("io exception occurred");
        }

        // Get the Network section
        String n = VMDescriptionNetwork(ovf);
        buf.append(n);

        buf.append("FEATURES=[ acpi=\"yes\" ]\n\n");

        buf.append("GRAPHICS = [type=\"vnc\", listen=\"127.0.0.1\", password=\"\\/|\\|67-yavin\"]\n\n");

        String c = VMDescriptionContext(ovf);
        buf.append(c);

        /*
         * If the cluster property is set, we add a requirements to the image
         * definition file, so that we can force the VM to be deployed on a
         * certain cluster
         * 
         * TODO: make it a per user choice
         * 
         * At this time this seem very ENG specific, since we need to keep some
         * of the machine reserved to a certain project and some other reserved
         * to internal usage
         */
        String cluster = ovf4oneProperties(CLUSTER, false);
        if (cluster != null && !"".equalsIgnoreCase(cluster)) {
            //            buf.append("REQUIREMENTS = \"CLUSTER = \\\"");
            //            buf.append(cluster);
            //            buf.append("\\\"\"\n");
        }
        //        buf.append("REQUIREMENTS = \"NAME = \\optimis1.leeds\\\"\"\n");
        // to a VM template that should not automatically be deployed (http://lists.opennebula.org/pipermail/users-opennebula.org/2012-April/018463.html)
        buf.append("REQUIREMENTS = \"FALSE\"\n");

        //        /*
        //         * @smendoza:  If using OpenNebula's default match-making scheduler in a hypervisor heterogeneous environment, it is a good idea to add an extra line like the following to the VM template to ensure its placement in a VMWare hypervisor enabled machine
        //         */
        //        buf.append("REQUIREMENTS = \"HYPERVISOR = \\\"");
        //        buf.append(ovf4oneProperties(HYPERVISOR, false));
        //        buf.append("\\\"\"\n");

        log.debug(weGotDisk);

        if (!((weGotKernel || weGotBootloader || weUseKVM) // this is mandatory for XEN only
                && (weGotBoot || !weUseKVM) // this is mandatory for KVM only
                && weGotDisk)) {
            StringBuilder msg = new StringBuilder(
                    "These problem in the OVF file prevent correct execution of the command:");
            msg.append((weGotKernel || weUseKVM) ? "" : "\n- Missing KERNEL specification for use with XEN");
            msg.append(
                    (weGotBootloader || weUseKVM) ? "" : "\n- Missing BOOTLOADER specification for use with XEN");
            msg.append((weGotBoot || !weUseKVM) ? "" : "\n- Missing BOOT device specification for use with KVM");
            msg.append(weGotDisk ? "" : "\n- Missing any DISK image specification");

            throw new DRPOneException(msg.toString() + Status, StatusCodes.BAD_OVF);

        }

        /*
         String[] rawData = { props.getProperty("raw.data.builder"),props.getProperty("raw.data.shadow_memory"),props.getProperty("raw.data.device_model"),props.getProperty("raw.data.boot"),props.getProperty("raw.TYPE")};
         String rawFormat = "RAW=[DATA=\"builder = '%s' \n shadow_memory = %s \n device_model = '%s' \n boot = \\\"%s\\\"\", \n TYPE=\"%s\"  \n ] \n";
         String raw = String.format(rawFormat,rawData);
         buf.append(raw); 
         */
        HashMap rawHM = new HashMap();
        rawHM.put("TYPE", "xen");
        rawHM.put("DATA", "builder = 'hvm'");// \nshadow_memory = 8 \ndevice_model = '/usr/lib/xen-4.0/bin/qemu-dm' \nboot = \\\"c\\\"");
        //        String raw = ONETemplatter.genSection("RAW", rawHM);
        //        String raw = "RAW=["
        //                + "DATA=\"builder = 'hvm' \n"
        //                + "shadow_memory = 8 \n"
        //                + "device_model = '/usr/lib/xen-4.0/bin/qemu-dm' \n"
        //                + "boot = \\\"c\\\"\", \n"
        //                + "TYPE=\"xen\"  \n"
        //                + "] \n";
        //        buf.append(raw);
        String template = "VCPU = 1\n" + "TEMPLATE_ID = 8\n" + "MEMORY = 1024\n"
                + "NAME = \"Ubuntu 12.04.1 x86_64 HVM (VNC) Instance\"\n" + "CPU = 1\n" + "DISK = [\n"
                + "IMAGE = \"Ubuntu 12.04.1 x86_64 HVM Base\",\n" + "IMAGE_UNAME = \"oneadmin\",\n"
                + "TARGET = \"hda\",\n" + "DRIVER = \"tap:qcow2:\"\n" + "]\n" + "OS = [\n"
                + "BOOTLOADER = \"/usr/lib/xen-4.0/boot/hvmloader\"\n" + "]\n" + "GRAPHICS = [\n"
                + "type=\"vnc\", \n" + "listen=\"0.0.0.0\", \n" + "KEYMAP = \"en-gb\", \n"
                + "password=\"password\"\n" + "]\n" + "RAW = [ DATA = \"builder = 'hvm'\",\n" + "TYPE = \"xen\" ]\n"
                + "NIC = [\n" + "MODEL = \"e1000\",\n" + "NETWORK = \"Internal NAT\",\n"
                + "NETWORK_UNAME = \"oneadmin\"\n" + "]\n";

        String qcow2 = "VCPU = 1\n" + "MEMORY = 1024\n" + "NAME = \"Sergio QCOW2\"\n" + "CPU = 1\n" + "DISK = [\n"
        //                + "TYPE=fs,\n"
                + "SOURCE= \"/opt/opennebula/var/datastores/1/dc443c87c4455d06ed96b694eb8c5131\",\n"
                //                + "PATH= \"/home/anthony/my-images/ubuntu_10g_x86_64.qcow2\",\n"
                + "TARGET = \"hda\",\n"
                //                + "DRIVER = \"tap:qcow2:\"\n"
                + "DRIVER = \"tap:qcow2:\"\n" + "]\n" + "OS = [\n"
                + "BOOTLOADER = \"/usr/lib/xen-4.0/boot/hvmloader\"\n" + "]\n" + "GRAPHICS = [\n"
                + "type=\"vnc\", \n" + "listen=\"0.0.0.0\", \n" + "KEYMAP = \"en-gb\", \n"
                + "password=\"password\"\n" + "]\n" + "RAW = [ DATA = \"builder = 'hvm'\",\n" + "TYPE = \"xen\" ]\n"
                + "NIC = [\n" + "MODEL = \"e1000\",\n" + "NETWORK = \"Internal NAT\",\n"
                + "NETWORK_UNAME = \"oneadmin\"\n" + "]\n";

        log.debug(buf);
        //        return qcow2;
        return buf.toString();
    }

    /**
     * Asks OpenNebula to obtain the info of the VM
     *
     * @param request
     * @param newVMID
     * @return
     */
    private String[] getIPs(HttpServletRequest request, int newVMID) {
        ArrayList<String> ips = new ArrayList<String>();
        String strFrom = "IP><![CDATA[";
        String strTo = "]]></IP>";
        Client ocaClient = getClient(request);

        OneResponse rc = VirtualMachine.info(ocaClient, newVMID);

        if (rc.isError()) {
            throw new DRPOneException("\nFailed getIP method!!\n" + "Failed while asking for the new VM IP"
                    + rc.getErrorMessage() + Status, StatusCodes.ONE_FAILURE);
        }
        String rpcMessage = rc.getMessage();

        int ipFrom = rpcMessage.indexOf(strFrom);
        int ipTo = rpcMessage.indexOf(strTo);

        while (ipFrom != -1 && ipTo != -1) {

            String tmpIP = rpcMessage.substring(ipFrom + strFrom.length(), ipTo);
            ips.add(tmpIP);

            ipFrom += strFrom.length();
            ipTo += strTo.length();

            //Search for the next appearance
            ipFrom = rpcMessage.indexOf(strFrom, ipFrom);
            ipTo = rpcMessage.indexOf(strTo, ipTo);

        }
        String[] ipsArray = ips.toArray(new String[ips.size()]);

        return ipsArray;
    }

    private OVFNetwork[] getNetworks(HttpServletRequest request, int newVMID) {

        //        String[] ips = this.getIPs(serverID);

        String[] ips = getIPs(request, newVMID);

        OVFNetwork[] nets = new OVFNetwork[ips.length];

        for (int i = 0; i < ips.length; ++i) {
            //public OVFNetwork(String connectionName, String ip, String mac, String netmask, String gateway)
            nets[i] = new OVFNetwork("public", ips[i], null, null, null);
        }

        return nets;
    }

    /**
     * Extracts from the *.ovf file all the information related to OS attributes
     * necessaries to generate OpenNebula's VM definition
     *
     * @param ovf
     * @return OS section of OpenNebula's VM definition
     */
    private String VMDescriptionOS(EmotiveOVF ovf) {
        StringBuilder buf = new StringBuilder();
        String attribute = "OS";
        HashMap hmSubAttr = new HashMap();

        // get ARCH from *.ovf
        String archName = ovf.getProductProperty(ARCH);
        if (archName == null && weUseKVM) {
            // if arch is not defined at *.ovf, got from default properties
            archName = ovf4oneProperties(ARCH, false);
            try {
                //if arch from *.ovf is an empty string, throw an exception
                if (archName != null && "".equals(archName.trim())) {
                    throw new DRPOneException(
                            "OVF and property files are both missing mandatory "
                                    + " architecutre specification for KVM.\n" + Status,
                            StatusCodes.NOT_ACCEPTABLE);
                } else {
                    hmSubAttr.put(ARCH, archName);
                }
            } catch (Exception e) {
            }
        }

        for (String productProperty : OS_subAttributes) {
            // String value = ovf.getProductProperty(productProperty);
            log.debug("getting the product property value of : " + productProperty);
            String value = ovf.getProductProperty(productProperty);

            // First rescue attempt. If the property is not in the
            // OVF, let's check the default values for this site.
            if (value == null || "".equals(value)) {
                value = ovf4oneProperties(productProperty, false);
            }

            if (value != null && !"".equals(value)) {
                // O.K., if I am here I got a value somehow, let's continue
                hmSubAttr.put(productProperty, value);

                if (productProperty == BOOT) {
                    if (BootType.isValid(value)) {
                        weGotBoot = true;
                    } else {
                        throw new DRPOneException("OVF file contains a bad value for BOOT " + value,
                                StatusCodes.BAD_OVF);
                    }
                } else if (productProperty == BOOTLOADER) {
                    weGotBootloader = true;
                } else if (productProperty == KERNEL) {
                    weGotKernel = true;
                }
            }
        }

        //        return ONETemplatter.genSection(attribute, hmSubAttr);

        return buf.toString();
    }

    /**
     *
     * Extract Disk Attributes for the VM template
     *
     * @param ovf file where the disk attributes will be extractred from
     * @return String with the disk description section for the ONE VM Template
     */
    private String VMDescriptionDisks(EmotiveOVF ovf) {
        StringBuilder buf = new StringBuilder();

        // Let's avoid some work to the JVM :)
        // 100 characters should avoid buffer resizing in most cases.
        // Don't worry, no buffer overflow ahead :)
        StringBuilder propertyName = new StringBuilder(100);
        log.debug("ovfdiskssize:" + ovf.getDisks().size());
        TargetedDisk sortedDisks[] = new TargetedDisk[ovf.getDisks().size()];

        int tgtDskIdx = 0;

        /*
         * It seems that OpenNebula requires that the disks are listed in the
         * physical order, while OVF has no constraint on the position of the
         * disks definition within the list. So I sort the disks according to
         * the physical device name:
         * 
         * TargetedDisk is a Comparable extension of OVFDisk that orders the
         * disks according to the device name, in the same way Linux does.
         */
        for (OVFDisk ovfDisk : ovf.getDisks().values()) {
            log.debug(ovfDisk.getId());
            sortedDisks[tgtDskIdx++] = new TargetedDisk(ovfDisk.getId(), ovfDisk, ovf);
        }
        log.debug("number of sorted disks:" + sortedDisks.length);
        Arrays.sort(sortedDisks);

        // retrieve from product property disk name
        if (ovf.getProductProperty(VM_BASEIMAGE) != null) {
            log.debug(ovf.getProductProperty(VM_BASEIMAGE));
            OVFDisk master_disk = ovf.getDisks().get(ovf.getProductProperty(VM_BASEIMAGE));

            log.debug(master_disk);
            log.debug("master disk id:" + master_disk.getId());
            propertyName.append(master_disk.getId());
            propertyName.append(PROP_PATORURL);

            TargetedDisk ovfDisk1 = new TargetedDisk("master", master_disk, ovf);
            buf.append("DISK = [\n");

            propertyName.append(master_disk.getId());
            propertyName.append(PROP_PATORURL);

            // If we have a path or URL specified, we have a pysical
            // disk. Else we have a pre-registered disk resource.
            String pathOrURL = ovfDisk1.getHref();
            log.debug("got image ref:" + pathOrURL);
            System.out.println("DRP4ONE - VMDescriptionDisks() > buf before: \n" + buf.toString());
            addVirtualDiskConfig(ovfDisk1, pathOrURL, ovf, propertyName, buf);
            System.out.println("DRP4ONE - VMDescriptionDisks() > buf after: \n" + buf.toString());
            buf.append("]\n");
            weGotDisk = true;
        }

        for (TargetedDisk ovfDisk : sortedDisks) {
            if (ovfDisk.getDskName().equals(ovf.getProductProperty(VM_BASEIMAGE))) {
                continue;
            }

            System.out.println("DRP4ONE - VMDescriptionDisks() > for: entro n l for" + buf.toString());

            buf.append("DISK = [\n");

            propertyName.delete(0, propertyName.length());
            log.debug("got disk name:" + ovfDisk.getDskName());
            System.out.println("DRP4ONE - VMDescriptionDisks() > for: got disk name:" + ovfDisk.getDskName());

            propertyName.append(ovfDisk.getDskName());
            propertyName.append(PROP_PATORURL);
            String pathOrURL = ovfDisk.getHref();
            log.debug("got image ref:" + pathOrURL);
            System.out.println("DRP4ONE - VMDescriptionDisks() > for: got image ref:" + pathOrURL);

            if (pathOrURL == null) {
                pathOrURL = ovf4oneProperties(propertyName.toString(), false);
            }

            propertyName.delete(ovfDisk.getDskNameLen(), propertyName.length());
            propertyName.append(PROP_TYPE);

            // String typeName =
            // ovf.getProductProperty(propertyName.toString());

            String typeName = ovf.getProductProperty(propertyName.toString());
            String propTypeName = ovf4oneProperties(propertyName.toString(), false);

            // When no disk type is specified, OpenNebula defaults to disk, and
            // we do so.
            DskType dskType = (typeName == null || "".equals(typeName.trim()))
                    ? ((propTypeName == null || "".equals(propTypeName.trim())) ? DskType.virtualDisk
                            : DskType.fromString(propTypeName))
                    : DskType.fromString(typeName);
            log.debug("Disk type" + dskType);
            System.out.println("DRP4ONE - VMDescriptionDisks() > for: Disk type" + dskType);

            if (dskType == null) {
                throw new DRPOneException(
                        "\n.OVF file is missing mandatory disk type for disk " + ovfDisk.getDskName(),
                        StatusCodes.NOT_FOUND);
            }

            Long size = ovfDisk.getCapacityMB();

            if (size == null && (dskType == DskType.virtualSwap || dskType == DskType.onTheFlyDisk)) {
                throw new DRPOneException("\n.OVF file is missing mandatory size specification for a disk ",
                        StatusCodes.BAD_OVF);
            }

            switch (dskType) {

            case virtualDisk:
                System.out.println("virtualDisk");

                addVirtualDiskConfig(ovfDisk, pathOrURL, ovf, propertyName, buf);
                System.out.println("DRP4ONE > Finishes addVirtualDiskConfig() virtualDisk");
                weGotDisk = true;
                break;
            case virtualSwap:
                System.out.println("virtualSwap");

                if (pathOrURL != null && !"".equals(pathOrURL)) {
                    buf.append("SOURCE = \"");
                    buf.append(pathOrURL);
                    buf.append("\",\n");
                }
                // else
                // throw new
                // DRPOneException("\n.OVF file is missing mandatory path or URL specification for swap disk named"
                // + ovfDisk.getDskName(),
                // StatusCodes.BAD_OVF);

                if (ovfDisk.getTarget() == null) {
                    throw new DRPOneException(
                            "Missing mandatory target specification for a swap disk named  " + ovfDisk.getDskName(),
                            StatusCodes.BAD_OVF);
                }
                buf.append("TYPE=swap,\n");
                buf.append("SIZE = ");
                buf.append(size);
                buf.append(",\n");
                buf.append("TARGET = \"");
                buf.append(ovfDisk.getTarget());
                buf.append("\"");
                // update the init.sh file to swapon the swap space

                arg2.add(ovfDisk.getTarget());

                try {
                    // bw.write("/sbin/swapon /dev/"+device_map.get(no_of_virtual_disk++)+"\n");
                } catch (Exception e) {
                    log.error("io exception occurred");
                }
                break;

            case blockDevice:
                System.out.println("blockDevice");

                buf.append("TYPE=block,\n");
                buf.append("SOURCE = \"");
                buf.append(pathOrURL);
                buf.append("\",\n");
                if (ovfDisk.getTarget() != null) {
                    buf.append("TARGET = \"");
                }
                buf.append(ovfDisk.getTarget());
                buf.append("\"");

                break;

            case onTheFlyDisk:
                System.out.println("onTheFlyDisk");

                propertyName.delete(ovfDisk.getDskNameLen(), propertyName.length());
                propertyName.append(PROP_FORMAT);
                log.debug("received on the fly disk");

                // //@madigiro - 21 july
                String format = ovf.getProductProperty(propertyName.toString());

                if (format == null) {
                    format = ovf4oneProperties(propertyName.toString(), false);
                }

                if (format == null) {
                    throw new DRPOneException(
                            "Missing mandatory format specification for an ont the fly disk image "
                                    + ovfDisk.getDskName(),
                            StatusCodes.BAD_OVF);
                }

                buf.append("TYPE=fs,\n");
                if (pathOrURL != null && !"".equals(pathOrURL)) {
                    buf.append("SOURCE = \"");
                    buf.append(pathOrURL);
                    buf.append("\",\n");
                }
                buf.append("SIZE = ");
                buf.append(size);
                buf.append(",\n");
                buf.append("FORMAT = \"");
                buf.append(format);
                buf.append("\",\n");
                if (ovfDisk.getTarget() != null) {
                    buf.append("TARGET = \"");
                }
                buf.append(ovfDisk.getTarget());
                buf.append("\"");

                arg1.add(ovfDisk.getTarget());

            }// switch finishes here

            typeName = "";
            pathOrURL = "";
            buf.append("]\n");
        }

        return buf.toString();
    }

    private String VMDescriptionNetwork(EmotiveOVF ovf) {

        StringBuilder buf = new StringBuilder();
        String tmp;

        // check for network attributes, if not available check the properties
        // file

        System.out.println("DRP4ONE - VMDescriptionNetwork()> ovf.getNetworks(): " + ovf.getNetworks());

        if (!ovf.getNetworks().isEmpty()) {

            //            added by smendoza
            //            String netSection = String.format("NIC = [ NETWORK_ID = %s ] \n",props.getProperty("net.id"));
            //            buf.append(netSection);

            // Network attributes
            netConnectNames = ovf4oneProperties(NET_CONNECTION_NAMES, false);
            for (OVFNetwork ovfNetwork : ovf.getNetworks().values()) {
                buf.append("NIC = [\n");
                String nicName = ovfNetwork.getConnectionName();

                // I am working on a new array, so I need to reset the separator
                String separator = "";

                if (nicName == null || "".equals(nicName)) {
                    // We supply IP and MAC for this NIC
                    tmp = ovfNetwork.getIp();
                    if (tmp != null) {
                        buf.append("IP = \"");
                        buf.append(tmp);
                        buf.append("\"");
                        separator = ",\n";
                    }

                    tmp = ovfNetwork.getMac();
                    if (tmp != null) {
                        buf.append(separator);
                        buf.append("MAC = \"");
                        buf.append(tmp);
                        buf.append("\"");
                    }

                } else {
                    // We ask OpenNebula to assign us IP and MAC
                    System.out.println("DRP4ONE - VMDescriptionNetwork()> nicName: " + nicName);

                    buf.append("NETWORK = \"");
                    buf.append(nicName);
                    buf.append("\" ");
                }
                buf.append("\n");
                nicNames.add(nicName);
                buf.append("]\n");
                System.out.println("DRP4ONE - VMDescriptionNetwork()> buf: " + buf);

                nicName = "";

            }

            log.debug("adding the networks configured in props..");
            log.debug("networks configured:" + netConnectNames);
            Scanner commaSperated = new Scanner(netConnectNames);
            commaSperated.useDelimiter(",");

            while (commaSperated.hasNext()) {
                String connectionName = commaSperated.next().trim();
                log.debug("connection name " + connectionName);
                Iterator<String> nicNamesIter = nicNames.iterator();
                while (nicNamesIter.hasNext()) {
                    log.debug("nic names config in input:" + nicNamesIter.next());
                }
                if (!nicNames.contains(connectionName)) {
                    //addNic(buf, connectionName);
                }
            }
        } else {
            log.debug("no network configured in ovf input, hence checking the network config from properties file");
            log.debug("networks configured:" + netConnectNames);
            Scanner commaSperated = new Scanner(netConnectNames);
            commaSperated.useDelimiter(",");

            while (commaSperated.hasNext()) {
                String connectionName = commaSperated.next().trim();
                // addNic(buf, connectionName);
                // buf.append("NIC = [\n");buf.append("NETWORK = \"");
                // buf.append(connectionName); buf.append("\"");
                // buf.append("]\n\n\n");
            }
        }

        return buf.toString();
    }

    private String VMDescriptionContext(EmotiveOVF ovf) {
        StringBuilder buf = new StringBuilder();
        // Context - requires again network attributes
        //
        // We list devices in order eth0, eth1, eth2... The context script will
        // get
        // them out and prepare the network configuration files.

        buf.append("CONTEXT = [\n");
        String separator = "";
        //        buf.append("hostname = \"optimis2.leeds\",");

        int ethNumber = 0;
        if (!ovf.getNetworks().isEmpty()) {
            for (OVFNetwork ovfNetwork : ovf.getNetworks().values()) {
                String nicName = ovfNetwork.getConnectionName();

                if (nicName == null || "".equals(nicName)) {
                    String tmp = ovfNetwork.getIp();
                    if (tmp != null) {
                        buf.append(separator);
                        buf.append("IP_");
                        buf.append(ethNumber);
                        buf.append(" = \"");
                        buf.append(tmp);
                        buf.append("\"\n");
                        separator = ",\n";
                    }

                    tmp = ovfNetwork.getMac();
                    if (tmp != null) {
                        buf.append(separator);
                        buf.append("MAC_");
                        buf.append(ethNumber);
                        buf.append(" = \"");
                        buf.append(tmp);
                        buf.append("\"\n");
                        separator = ",\n";

                    }

                } else {
                    addNetworkConfigToContext(buf, separator, ethNumber, nicName);
                }
                ethNumber++;
            }

            log.debug("adding the networks configured in props..");
            log.debug("networks configured:" + netConnectNames);
            Scanner commaSperated = new Scanner(netConnectNames);
            commaSperated.useDelimiter(",");

            while (commaSperated.hasNext()) {
                String connectionName = commaSperated.next().trim();
                if (!nicNames.contains(connectionName)) {
                    addNetworkConfigToContext(buf, separator, ethNumber, connectionName);
                    log.debug("adding network config:" + connectionName);
                    ethNumber++;
                }
            }
        } else {

            log.debug("no network configured in ovf input, hence checking the network config from properties file");
            log.debug("networks configured:" + netConnectNames);
            Scanner commaSperated = new Scanner(netConnectNames);
            commaSperated.useDelimiter(",");

            while (commaSperated.hasNext()) {
                String connectionName = commaSperated.next().trim();
                addNetworkConfigToContext(buf, separator, ethNumber, connectionName);
                ethNumber++;
                // buf.append("NIC = [\n");buf.append("NETWORK = \"");
                // buf.append(connectionName); buf.append("\"");
                // buf.append("]\n\n\n");
            }

        }

        Iterator<String> home_iter = arg1.iterator();
        Iterator<String> swap_iter = arg2.iterator();
        buf.append("HOME = \"");
        while (home_iter.hasNext()) {

            buf.append(home_iter.next());
            buf.append(" ");

        }

        buf.append("\",\n");
        buf.append("SWAP = \"");
        while (swap_iter.hasNext()) {

            buf.append(swap_iter.next());
            buf.append(" ");
        }
        buf.append("\"\n");
        //        buf.append("FILES=" + "\"" + scriptlocation + "/init.sh \"");
        buf.append("]\n");
        return buf.toString();
    }

    private void addVirtualDiskConfig(TargetedDisk ovfDisk1, String pathOrURL, EmotiveOVF ovf,
            StringBuilder propertyName, StringBuilder buf) {

        if (pathOrURL == null) {
            pathOrURL = ovf4oneProperties(propertyName.toString(), false);
        }

        if (pathOrURL == null || "".equals(pathOrURL)) {
            StringBuilder bufx = new StringBuilder(
                    "\n.OVF file is missing mandatory path or url of the image for disk id=\"");
            buf.append(ovfDisk1.getDskName());
            buf.append(" and no default is provided ");
            throw new DRPOneException(bufx.toString(), StatusCodes.BAD_OVF);
        }
        if (!pathOrURL.startsWith(FILE_PATH_SEPARATOR)) {
            System.out.println("DRP4ONE - addVirtualDiskConfig()> FILE_PATH_SEPARATOR: " + FILE_PATH_SEPARATOR);
            String image;
            if (pathOrURL.startsWith(ONE_PROTOCOL)) {
                image = pathOrURL.substring(ONE_PROTOCOL_LEN).trim();
            } else {

                System.out
                        .println("DRP4ONE - addVirtualDiskConfig()> Path sense protocol, pathOrURL: " + pathOrURL);

                image = pathOrURL.trim();

                //Sergio: added the home where the images are hosted
                // Sergio commented, because it will be necessary to add images at the ONE datastore
                //                image = imgsHome + "/" + image;
            }

            if ("".equals(image)) {
                StringBuilder bufx = new StringBuilder(
                        "\n.OVF file has an invalid (empty) path or url of the image for disk id=\"");
                buf.append(ovfDisk1.getDskName());
                buf.append(" and no default is provided ");
                throw new DRPOneException(bufx.toString(), StatusCodes.BAD_OVF);
            }

            // Su solo aade IMAGE = , esta coma no debe ir!!
            System.out.println("DRP4ONE - addVirtualDiskConfig()> image: " + image);
            buf.append("IMAGE = \"");
            buf.append(image);
            //Sergio comenta la siguiente linea (2013/05/14)
            //            buf.append("\", \n");
            buf.append("\" \n");

            if (ovfDisk1.getTarget() != null) {
                buf.append("TARGET = \"");
                buf.append(ovfDisk1.getTarget());
                buf.append("\"");
            }

        } else {
            if (ovfDisk1.getTarget() == null) {
                throw new DRPOneException(
                        "Missing mandatory target specification for a disk " + ovfDisk1.getDskName(),
                        StatusCodes.BAD_OVF);
            }

            HashMap<String, String> diskTemplate = new HashMap<String, String>();
            diskTemplate.put("NAME", ovfDisk1.getDskName());
            diskTemplate.put("PATH", ovfDisk1.getHref());

            //            String imgID = ONETemplatter.ONEImageCreate(diskTemplate);
            //            diskTemplate.put("IMAGE_ID", imgID);

            String disk = ""
                    //                    + "IMAGE = \"" + ovfDisk1.getDskName()+ "\",\n"
                    //                    + "IMAGE_UNAME = \"anthony\",\n"
                    + "IMAGE_ID = " + diskTemplate.get("IMAGE_ID") + " \n";
            //                    + "TYPE = \"DISK\",\n"
            //                    + "CLONE = yes,\n"
            //                    + "SOURCE = \"" + ovfDisk1.getHref() + "\",\n"
            //                    + "TARGET = \"sda\",\n"
            //                    + "DISK_TYPE = \"BLOCK\",\n"
            //                    + "DRIVER = \"raw:\"\n";
            //                    + "DRIVER = \"tap:qcow2:,tap:aio\"\n";

            buf.append(disk);

            // We are using a physical disk image
            //            buf.append("TYPE=fs,\n");
            //            buf.append("SOURCE = \"");
            //            buf.append(pathOrURL);
            //            buf.append("\",\n");
            //            buf.append("TARGET = \"");
            //            buf.append(ovfDisk1.getTarget());
            //            buf.append("\"");

        }

        String separator = ",\n";

        // This COULD be a good system image...

    }

    private void addNic(StringBuilder buf, String connectionName) {
        // TODO Auto-generated method stub
        log.debug("Adding the network config :" + connectionName);
        System.out.println("*********** I've entered addNIC()!!!:");
        System.out.println("*********** StringBuilder buf: " + buf);
        System.out.println("*********** String connectionName: " + connectionName);
        buf.append("NIC = [\n");
        buf.append("NETWORK = \"");
        buf.append(connectionName);
        buf.append("\" \n");
        buf.append("]\n");

    }

    private void addNetworkConfigToContext(StringBuilder buf, String separator, int ethNumber, String nicName) {
        buf.append(separator);
        buf.append("IP_");
        buf.append(ethNumber);
        buf.append(" = \"$NIC[IP, NETWORK=\\\"");
        buf.append(nicName);
        buf.append("\\\"]\",\n");
        buf.append("MAC_");
        buf.append(ethNumber);
        buf.append(" = \"$NIC[MAC, NETWORK=\\\"");
        buf.append(nicName);
        buf.append("\\\"]\",\n");
        buf.append("NETMASK_");
        buf.append(ethNumber);
        buf.append("=\"$NETWORK[NETMASK, NAME=\\\"");
        buf.append(nicName);
        buf.append("\\\"]\",\n");
        buf.append("GATEWAY_");
        buf.append(ethNumber);
        buf.append("=\"$NETWORK[GATEWAY, NAME=\\\"");
        buf.append(nicName);
        buf.append("\\\"]\",\n");
        buf.append("BROADCAST_");
        buf.append(ethNumber);
        buf.append("=\"$NETWORK[BROADCAST, NAME=\\\"");
        buf.append(nicName);
        buf.append("\\\"]\",\n");
        /*
         * Great OpenNebula feature :) fixed size networks have NETWORK, ranged
         * networks have NETWORK_ADDRESS Therefore I set up NE
         */
        buf.append("NETWORK_ADDRESS_");
        buf.append(ethNumber);
        buf.append("=\"$NETWORK[NETWORK, NAME=\\\"");
        buf.append(nicName);
        buf.append("\\\"]\",\n");
        buf.append("HOSTNAME=\"venuscdebianbase-$VMID\",\n");
        separator = ",\n";

    }

    /*
     * private void notifyUsageTracker(int vmId, String user) {
     * 
     * String usageTrackerUrl = ovf4oneProperties(USAGE_TRACKER_URL,false);
     * 
     * // if this property is empty (empty string or null) disable // the
     * tracker notifications. if( usageTrackerUrl == null ||
     * "".equals(usageTrackerUrl.trim())) return;
     * 
     * UsageTrackerRestAPI ut = new UsageTrackerRestAPI(usageTrackerUrl);
     * 
     * VMUsageRecord ur = new VMUsageRecord();
     * 
     * // set the identity of the creator (ovf4one) ur.setCreatorId(
     * this.getClass().getName() );
     * 
     * // set the creation time (NOW) Calendar cal = Calendar.getInstance();
     * ur.setCreateTime(cal); ur.setStartTime(cal); // who actually consumed the
     * resource (received in http header) ur.setConsumerId( (user==null) ?
     * "ovf4one unauthenticated" : user);
     * 
     * String resourceOwner = ovf4oneProperties(INFRASTRUCTURE_ID, false);
     * 
     * resourceOwner = ( resourceOwner == null ) ? "unspecified infrasturecture"
     * : resourceOwner;
     * 
     * ur.setResourceOwner(resourceOwner);
     * 
     * ur.setRefVM(""+vmId);
     * 
     * try { ut.insertUsageRecord(ur); } catch(Exception e) { // Ignore any
     * exception but log it
     * log.warn("Notify Usage Tracker error in insertUsageRecord()",e);
     * 
     * }
     * 
     * }
     */

    /*
     * ==============================================================
     * ==============================================================
     * 
     * private helpers for the getCompute method
     */
    private OCAComputeWrapper parseOcaCompute(String s) {
        OCAComputeWrapper rv = null;
        StringBuilder cause = new StringBuilder();
        try {
            rv = OCAComputeWrapperFactory.parse(s);
        } catch (SAXException se) {
            throw new DRPOneException("XML Parsing error", se, StatusCodes.INTERNAL);
        } catch (JAXBException e) {
            if (e instanceof PropertyException) {
                cause.append("Access to property failed: " + e.getErrorCode());
            } else if (e instanceof MarshalException) {
                cause.append("Marshalling failed: " + e.getLocalizedMessage());
            } else if (e instanceof UnmarshalException) {
                cause.append("Unmarshalling failed: " + e.getCause());
            } else if (e instanceof ValidationException) {
                cause.append("XML Validation failed: " + e.getErrorCode());
            } else {
                cause.append("Unespected " + e.getErrorCode());
                cause.append(e.getClass().getName());
                cause.append(": ");
            }
            cause.append(e.getMessage());
            log.error(cause.toString());
            if (log.isTraceEnabled()) {
                log.trace(cause, e);
            }
            throw new DRPOneException(cause.toString(), e, StatusCodes.ONE_FAILURE);
        }
        return rv;
    }

    /*
     * ==============================================================
     * ==============================================================
     * 
     * private helpers for the getComputes method
     */
    private OCAComputeListWrapper parseOcaComputeList(String s) {
        OCAComputeListWrapper rv = null;
        StringBuilder cause = new StringBuilder();
        try {
            rv = OCAComputeListWrapperFactory.parseList(s);
        } catch (SAXException se) {
            throw new DRPOneException("XML Parsing error", se, StatusCodes.INTERNAL);
        } catch (JAXBException e) {
            if (e instanceof PropertyException) {
                cause.append("Access to property failed: " + e.getErrorCode());
            } else if (e instanceof MarshalException) {
                cause.append("Marshalling failed: " + e.getLocalizedMessage());
            } else if (e instanceof UnmarshalException) {
                cause.append("Unmarshalling failed: " + e.getCause());
            } else if (e instanceof ValidationException) {
                cause.append("XML Validation failed: " + e.getErrorCode());
            } else {
                cause.append("Unespected " + e.getErrorCode());
                cause.append(e.getClass().getName());
                cause.append(": ");
            }
            cause.append(e.getMessage());
            log.error(cause.toString());
            if (log.isTraceEnabled()) {
                log.trace(cause, e);
            }
            throw new DRPOneException(cause.toString(), e, StatusCodes.ONE_FAILURE);
        }
        return rv;

    }

    // @madigiro
    // Saint - Thu Nov 10 10:39:12 2011
    //
    // Added a flag to not re-read the properties each time we work on them.
    String ovf4oneProperties(String ovfProperty, boolean refresh) {
        if (refresh || (props == null)) {
            props = reloadProperties();
        }

        return props.getProperty(ovfProperty);
    }

    private Properties getProperties() {
        if (props == null) {
            props = reloadProperties();
        }
        return props;
    }

    private Properties reloadProperties() {
        Properties props = new Properties();
        try {
            InputStream is = getClass().getResourceAsStream(PROPFILE);

            // read by smendoza
            //            String ONEproperties = ovf4oneProperties.properties;
            //            InputStream is = new ByteArrayInputStream(ONEproperties.getBytes("UTF-8"));
            props.load(is);
            // close the stream NOW, don't wait for the garbage collector
            is.close();

        } catch (FileNotFoundException e) {
            throw new OpenNebulaConfigurationError("\n.File NOT FOUND " + PROPFILE + ": " + e.getMessage());
        } catch (IOException e) {
            throw new OpenNebulaConfigurationError("\n. IO exception  " + PROPFILE + ": " + e.getMessage());
        }

        return props;
    }

    // Saint - Thu Oct 6 11:47:30 2011
    //
    // Method to see if we can connect to the VM on port 22 on some
    // nic.
    private boolean port22Reached(String ipAddress) {
        boolean gotPort22Connection = false;

        try {

            InetAddress toPoll = InetAddress.getByName(ipAddress);
            boolean reachable = false;
            try {
                // We have to answer within a WS timeout
                reachable = toPoll.isReachable(5000);
            } catch (IOException e) {
                // same as unreachable, log the problem
                if (log.isDebugEnabled()) {
                    log.error(e);
                } else {
                    log.error(e.getMessage());
                }
            }

            if (reachable) {
                // see if we can ssh connect to port 22
                try {
                    Socket socket = new Socket(toPoll, 22);
                    gotPort22Connection |= socket.isConnected();
                    socket.close();
                } catch (IOException e) {
                    // Happens when there's no one listening
                    // on port 22, for example. Anyway, it
                    // means we can't connect
                }

            }

        } catch (UnknownHostException e) {
            // Ignore, it's not a valid ip!
        } catch (SecurityException e) {

            if (log.isDebugEnabled()) {
                log.fatal(e);
            } else {
                log.fatal(e.getMessage());
            }

            throw e;

        }
        return gotPort22Connection;

    }

    // /Saint
    // Saint - Thu Oct 6 17:32:22 2011
    //
    // Handles the OpenNebula to libvirt state conversion
    private State one2libvrtStatus(int vmStatus, int lcmStatus, boolean gotPort22Connection) {
        State rv = null;

        if (lcmStatus == LcmStatusCodes.UNKNOWN) {
            return State.NOSTATE;
        }

        switch (vmStatus) {
        case VmStatusCodes.INIT:
            rv = State.NOSTATE;
            break;

        case VmStatusCodes.PENDING:
            rv = State.NOSTATE;
            break;

        case VmStatusCodes.HOLD:
            rv = State.BLOCKED;
            break;

        case VmStatusCodes.ACTIVE:
            //rv = (gotPort22Connection) ? State.RUNNING_READY : State.RUNNING;
            rv = (gotPort22Connection) ? State.RUNNING_READY : State.RUNNING;
            break;

        case VmStatusCodes.STOPPED:
            rv = State.SHUTOFF;
            break;

        case VmStatusCodes.SUSPENDED:
            rv = State.PAUSED;
            break;

        case VmStatusCodes.DONE:
            rv = State.SHUTOFF;
            break;

        case VmStatusCodes.FAILED:
            rv = State.CRASHED;
            break;

        default:
            rv = State.NOSTATE;

        }

        return rv;

    }

    private String one2libvirtStatusAsText(int vmStatus, int lcmStatus, boolean gotPort22Connection) {
        switch (one2libvrtStatus(vmStatus, lcmStatus, gotPort22Connection)) {
        case NOSTATE:
            return "NOSTATE";

        case BLOCKED:
            return "BLOCKED";

        //case RUNNING_READY:
        case RUNNING_READY:
            return "RUNNING_AVAILABLE";

        case RUNNING:
            return "RUNNING";

        case SHUTOFF:
            return "SHUTOFF";

        case PAUSED:
            return "PAUSED";

        case CRASHED:
            return "CRASHED";

        default:
            return "NOSTATE";
        }
    }

    private void mount_disks() {
    }

    /**
     * ********************* NODE MANAGEMENT methods.
     * **************************
     */

    /* =================== END METHODS ==================== */
    public static void main(String[] args) throws Exception {
        // A simple test for DRP4OVF methods
        Client ocaClient = null;

        // First case: occi-compute create http://localhost:8080/ovf4one
        // xxxx.xml
        try {
            ocaClient = new Client();
        } catch (UniformInterfaceException u) {
            System.out.println("Error main : " + u.getMessage());
            ClientResponse cl = u.getResponse();
            if (cl.getStatus() == 500) {
                throw new DRPOneException(
                        "Internal error, if ocaClient is null please insert correct ocaclient and try again.",
                        StatusCodes.INTERNAL);
            } else if (cl.getStatus() == 404) {
                throw new DRPOneException(
                        "Internal error, incorrect user or password, insert correct user or/and password and try againn",
                        StatusCodes.UNAUTHORIZED);
            } else {
                throw new DRPOneException("Error generic: " + u.getMessage(), StatusCodes.BAD_REQUEST);
            }
        }
        try {
            OneResponse rc = VirtualMachine.info(ocaClient, 14);
            if (rc.isError()) {
                System.out.println("Error in the method " + rc.getClass().getMethods() + rc.getErrorMessage());
            }
            System.out.println("Print result of method : " + rc.getMessage());
        } catch (UniformInterfaceException uex) {

            System.err.print("An error ocurred: ");
            ClientResponse cr = uex.getResponse();
            if (cr.getStatus() == 426) {
                throw new DRPOneException("Name was already assigned in this VtM", StatusCodes.NAME_EXIST);
            } else if (cr.getStatus() == 420) {
                throw new DRPOneException("Virtual Machine detected some problem",
                        StatusCodes.INTERNAL_ERROR_PARSE);
            } else if (cr.getStatus() == 425) {
                throw new DRPOneException("Not enough resources (for example memory)", StatusCodes.NOT_RESOURCES);
            } else if (cr.getStatus() == 427) {
                throw new DRPOneException("Creation failed", StatusCodes.VM_NOT_EXIST);
            } else if (cr.getStatus() == 428) {
                throw new DRPOneException("No available nodes", StatusCodes.NOT_AVAILABLE_NODES);
            } else if (cr.getStatus() == 432) {
                throw new DRPOneException("Cannot recognize address", StatusCodes.CANNOT_ADDRESS);
            } else if (cr.getStatus() == 433) {
                throw new DRPOneException("Domain with this name already present in the system",
                        StatusCodes.DOMAIN_NAME_EXIST);
            } else if (cr.getStatus() == 424) {
                throw new DRPOneException("Error 424", StatusCodes.FAILED_DEPENDECIES);
            } else {
                throw new DRPOneException("Other Undefined Error", StatusCodes.BAD_REQUEST);
            }
        } // end catch

    }

    private Client getClient(HttpServletRequest request) throws DRPOneException {
        /*
         String userid = ""; // "venus";
         String endpoint = ovf4oneProperties(ONE_XMLRPC, false);
         Client rv = null;
            
         userid = SecureSessionInfo.getUserDN(request);
            
         // TODO: u
         rv = clientProvider.provideClient(userid, ocaClientProviderURL,
         ocaClientProviderQuery, endpoint, getProperties());
         */
        Client rv = null;
        try {
            String secret = this.user + ":" + this.passwd;
            rv = new Client(secret, this.rpcserver);
        } catch (Exception e) {
            throw new DRPOneException();
        }

        return rv;
    }

    /*
     * Other methods vor emotivecloud interoperability
     */
    @GET
    @Path("/environments/{envid}/status")
    // antic state, falta el destroy per arreglar, al VtM ho fa be
    @Produces("text/plain")
    public String getState(@PathParam("envid") String envId, @Context HttpServletRequest request)
            throws DRPOneException {
        String status = "Unknown";

        OneResponse rc = getComputeHelper(envId, request);

        OCAComputeWrapper oca = rc2OCA(rc);

        Collection<OCANicWrapper> nicList = oca.getTemplate().getNics().values();

        int vmStatus = oca.getState();
        int lcmState = oca.getLcmState();
        boolean doThePoll = vmStatus == VmStatusCodes.ACTIVE && lcmState == LcmStatusCodes.RUNNING;

        boolean gotPort22Connection = false;

        if (doThePoll) {
            for (OCANicWrapper nic : nicList) {
                String ipAddress = nic.getIp();

                if (ipAddress != null) {
                    gotPort22Connection |= port22Reached(ipAddress);
                }

            }
        }

        status = one2libvirtStatusAsText(vmStatus, lcmState, gotPort22Connection);

        return status;
    }

    @GET
    @Path("/environments/{envid}/{taskid}")
    @Produces("text/plain")
    public String getActivityStatus(@PathParam("envid") String envid, @PathParam("taskid") String taskid)
            throws DRPOneException {
        // String status = null;
        throwNotImplemented("getActivityStatus(String, String)");
        return null;
    }

    private void throwNotImplemented(String name) throws DRPOneException {
        StringBuilder buf = new StringBuilder(39 + name.length());
        buf.append("Emotve specific method ");
        buf.append(name);
        buf.append(" not implemented");

        throw new DRPOneException(buf.toString(), StatusCodes.NOT_IMPLEMENTED);

    }

    /*
     * This inner class is used to sort the disks so thant they are presented to
     * virsh ordered according to their target/physical device name
     * 
     * It "simply adds Comparable to OVFDisk". The OVFDisk behaviour is supplied
     * by the original OVFDisk itself.
     */
    class TargetedDisk extends OVFDisk implements Comparable<TargetedDisk> {

        public final static String PROP_TARGET = ".TARGET";
        String target;
        String dskName;
        int dskNameLen;
        OVFDisk ovfDisk;

        public int compareTo(TargetedDisk that) {
            if (this.target == null && that.target == null) {
                return 0;
            }
            if (this.target == null) {
                return 1;
            } else if (that.target == null) {
                return -1;
            } else {
                return this.target.compareTo(that.target);
            }
        }

        public TargetedDisk(String dskName1, OVFDisk newOvfDisk, EmotiveOVF ovf) {
            ovfDisk = newOvfDisk;
            dskName = newOvfDisk.getId();
            if (dskName == null) {
                throw new DRPOneException("\n.OVF file is missing mandatory disk Id ", StatusCodes.NOT_ACCEPTABLE);
            }

            dskNameLen = dskName.length();
            if (dskNameLen == 0) {
                throw new DRPOneException("\n.OVF file has a zero lenght ID", StatusCodes.FAILED_DEPENDECIES);
            }

            String propertyName = dskName + PROP_TARGET;

            target = ovf.getProductProperty(propertyName.toString());

            if (target == null) // @madigiro - 21 july
            {
                target = ovf4oneProperties(dskName1 + PROP_TARGET, false);
            }

        }

        public boolean equals(Object obj) {
            if (!(obj instanceof TargetedDisk)) {
                return false;
            }

            return target.equals(((TargetedDisk) obj).target);
        }

        public Long getCapacityMB() {
            return ovfDisk.getCapacityMB();
        }

        public String getHref() {
            return ovfDisk.getHref();
        }

        public String getId() {
            return ovfDisk.getId();
        }

        public int hashCode() {
            return ovfDisk.hashCode();
        }

        public String toString() {
            return ovfDisk.toString();
        }

        public String getTarget() {
            return target;
        }

        public void setTarget(String target) {
            this.target = target;
        }

        public String getDskName() {
            return dskName;
        }

        public void setDskName(String dskName) {
            this.dskName = dskName;
        }

        public int getDskNameLen() {
            return dskNameLen;
        }

        public void setDskNameLen(int dskNameLen) {
            this.dskNameLen = dskNameLen;
        }
    }
}