com.dell.asm.asmcore.asmmanager.app.rest.DeploymentService.java Source code

Java tutorial

Introduction

Here is the source code for com.dell.asm.asmcore.asmmanager.app.rest.DeploymentService.java

Source

/**************************************************************************
 *   Copyright (c) 2013 - 2016 Dell Inc. All rights reserved.             *
 *                                                                        *
 * DELL INC. CONFIDENTIAL AND PROPRIETARY INFORMATION. This software may  *
 * only be supplied under the terms of a license agreement or             *
 * nondisclosure agreement with Dell Inc. and may not be copied or        *
 * disclosed except in accordance with the terms of such agreement.       *
 **************************************************************************/
package com.dell.asm.asmcore.asmmanager.app.rest;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Path;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.ListUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.log4j.Logger;
import org.hibernate.Hibernate;
import org.quartz.JobDetail;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.impl.triggers.SimpleTriggerImpl;

import com.dell.asm.alcm.client.model.WizardStatus;
import com.dell.asm.asmcore.asmmanager.AsmManagerMessages;
import com.dell.asm.asmcore.asmmanager.app.AsmManagerApp;
import com.dell.asm.asmcore.asmmanager.client.deployment.AsmDeployerLogEntry;
import com.dell.asm.asmcore.asmmanager.client.deployment.Deployment;
import com.dell.asm.asmcore.asmmanager.client.deployment.DeploymentDevice;
import com.dell.asm.asmcore.asmmanager.client.deployment.DeploymentFilterResponse;
import com.dell.asm.asmcore.asmmanager.client.deployment.DeploymentHealthStatusType;
import com.dell.asm.asmcore.asmmanager.client.deployment.DeploymentNamesType;
import com.dell.asm.asmcore.asmmanager.client.deployment.DeploymentStatusType;
import com.dell.asm.asmcore.asmmanager.client.deployment.DeploymentValid;
import com.dell.asm.asmcore.asmmanager.client.deployment.IDeploymentService;
import com.dell.asm.asmcore.asmmanager.client.deployment.PuppetLogEntry;
import com.dell.asm.asmcore.asmmanager.client.deployment.RejectedServer;
import com.dell.asm.asmcore.asmmanager.client.deployment.SelectedNIC;
import com.dell.asm.asmcore.asmmanager.client.deployment.SelectedServer;
import com.dell.asm.asmcore.asmmanager.client.deployment.ServerNetworkObjects;
import com.dell.asm.asmcore.asmmanager.client.deployment.ServiceDefinition;
import com.dell.asm.asmcore.asmmanager.client.deployment.VM;
import com.dell.asm.asmcore.asmmanager.client.deviceinventory.CompliantState;
import com.dell.asm.asmcore.asmmanager.client.deviceinventory.DeviceHealth;
import com.dell.asm.asmcore.asmmanager.client.deviceinventory.DeviceState;
import com.dell.asm.asmcore.asmmanager.client.deviceinventory.FirmwareComplianceReport;
import com.dell.asm.asmcore.asmmanager.client.discovery.DeviceType;
import com.dell.asm.asmcore.asmmanager.client.networkconfiguration.Fabric;
import com.dell.asm.asmcore.asmmanager.client.networkconfiguration.Interface;
import com.dell.asm.asmcore.asmmanager.client.servicetemplate.Network;
import com.dell.asm.asmcore.asmmanager.client.servicetemplate.ServiceTemplate;
import com.dell.asm.asmcore.asmmanager.client.servicetemplate.ServiceTemplateCategory;
import com.dell.asm.asmcore.asmmanager.client.servicetemplate.ServiceTemplateComponent;
import com.dell.asm.asmcore.asmmanager.client.servicetemplate.ServiceTemplateComponent.ServiceTemplateComponentType;
import com.dell.asm.asmcore.asmmanager.client.servicetemplate.ServiceTemplateSetting;
import com.dell.asm.asmcore.asmmanager.client.servicetemplate.ServiceTemplateSettingIDs;
import com.dell.asm.asmcore.asmmanager.client.util.ServiceTemplateClientUtil;
import com.dell.asm.asmcore.asmmanager.db.AddOnModuleComponentsDAO;
import com.dell.asm.asmcore.asmmanager.db.DeploymentDAO;
import com.dell.asm.asmcore.asmmanager.db.DeploymentNamesRefDAO;
import com.dell.asm.asmcore.asmmanager.db.DeviceGroupDAO;
import com.dell.asm.asmcore.asmmanager.db.DeviceInventoryComplianceDAO;
import com.dell.asm.asmcore.asmmanager.db.DeviceInventoryDAO;
import com.dell.asm.asmcore.asmmanager.db.FirmwareRepositoryDAO;
import com.dell.asm.asmcore.asmmanager.db.GenericDAO;
import com.dell.asm.asmcore.asmmanager.db.ServiceTemplateDAO;
import com.dell.asm.asmcore.asmmanager.db.entity.AddOnModuleComponentEntity;
import com.dell.asm.asmcore.asmmanager.db.entity.AddOnModuleEntity;
import com.dell.asm.asmcore.asmmanager.db.entity.DeploymentEntity;
import com.dell.asm.asmcore.asmmanager.db.entity.DeploymentNamesRefEntity;
import com.dell.asm.asmcore.asmmanager.db.entity.DeploymentUserRefEntity;
import com.dell.asm.asmcore.asmmanager.db.entity.DeviceGroupEntity;
import com.dell.asm.asmcore.asmmanager.db.entity.DeviceInventoryComplianceEntity;
import com.dell.asm.asmcore.asmmanager.db.entity.DeviceInventoryEntity;
import com.dell.asm.asmcore.asmmanager.db.entity.FirmwareRepositoryEntity;
import com.dell.asm.asmcore.asmmanager.db.entity.ServiceTemplateEntity;
import com.dell.asm.asmcore.asmmanager.db.entity.VMRefEntity;
import com.dell.asm.asmcore.asmmanager.exception.AsmManagerCheckedException;
import com.dell.asm.asmcore.asmmanager.exception.AsmManagerNoServerException;
import com.dell.asm.asmcore.asmmanager.exception.AsmManagerRuntimeException;
import com.dell.asm.asmcore.asmmanager.tasks.FirmwareUpdateJob;
import com.dell.asm.asmcore.asmmanager.tasks.ServiceDeploymentJob;
import com.dell.asm.asmcore.asmmanager.util.AsmManagerUtil;
import com.dell.asm.asmcore.asmmanager.util.DeploymentValidator;
import com.dell.asm.asmcore.asmmanager.util.ProxyUtil;
import com.dell.asm.asmcore.asmmanager.util.PuppetModuleUtil;
import com.dell.asm.asmcore.asmmanager.util.ServiceTemplateUtil;
import com.dell.asm.asmcore.asmmanager.util.ServiceTemplateValidator;
import com.dell.asm.asmcore.asmmanager.util.brownfield.BrownfieldUtil;
import com.dell.asm.asmcore.asmmanager.util.deployment.DeploymentEnvironment;
import com.dell.asm.asmcore.asmmanager.util.deployment.DnsUtil;
import com.dell.asm.asmcore.asmmanager.util.deployment.FilterEnvironment;
import com.dell.asm.asmcore.asmmanager.util.deployment.HostnameUtil;
import com.dell.asm.asmcore.asmmanager.util.deployment.MigrationDeviceUtils;
import com.dell.asm.asmcore.asmmanager.util.deployment.NetworkingUtil;
import com.dell.asm.asmcore.asmmanager.util.deployment.ServerFilteringUtil;
import com.dell.asm.asmcore.asmmanager.util.deployment.ServiceDeploymentUtil;
import com.dell.asm.asmcore.asmmanager.util.firmwarerepository.FirmwareUtil;
import com.dell.asm.asmcore.user.model.IUserResource;
import com.dell.asm.asmcore.user.model.User;
import com.dell.asm.asmdeployer.client.AsmDeployerComponentStatus;
import com.dell.asm.asmdeployer.client.AsmDeployerStatus;
import com.dell.asm.asmdeployer.client.IAsmDeployerService;
import com.dell.asm.common.utilities.ASMCommonsUtils;
import com.dell.asm.i18n2.AsmDetailedMessageList;
import com.dell.asm.i18n2.EEMILocalizableMessage;
import com.dell.asm.localizablelogger.LocalizableMessageService;
import com.dell.asm.localizablelogger.LogMessage;
import com.dell.asm.rest.common.AsmConstants;
import com.dell.asm.rest.common.exception.LocalizedWebApplicationException;
import com.dell.asm.rest.common.model.Link;
import com.dell.asm.rest.common.util.FilterParamParser;
import com.dell.asm.rest.common.util.PaginationParamParser;
import com.dell.asm.rest.common.util.RestUtil;
import com.dell.asm.rest.common.util.SortParamParser;
import com.dell.pg.asm.identitypool.api.network.INetworkService;
import com.dell.pg.asm.identitypoolmgr.ioidentity.impl.IOIdentityMgr;
import com.dell.pg.asm.identitypoolmgr.network.impl.IPAddressPoolMgr;
import com.dell.pg.orion.common.utilities.MarshalUtil;
import com.dell.pg.orion.common.utilities.PingUtil;
import com.dell.pg.orion.jobmgr.IJobManager;
import com.dell.pg.orion.jobmgr.JobManager;
import com.dell.pg.orion.security.encryption.EncryptionDAO;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;

/**
 * Implementation of Device Inventory REST Service for ASM Manager.
 */
@Path("/Deployment")
public class DeploymentService implements IDeploymentService {

    private static final Logger logger = Logger.getLogger(DeploymentService.class);
    private static final Set<String> validSortColumns = new HashSet<>();
    private static final ObjectMapper OBJECT_MAPPER = buildObjectMapper();
    private static final String DEFAULT_DEPLOYMENT_ID = "1000";
    private static final String SEVERITY_COLUMN = "severity";

    public static String VM_NAMES = "vm_names";
    public static String OS_HOST_NAMES = "os_host_names";
    public static String STORAGE_NAMES = "storage_volumes";

    static ObjectMapper buildObjectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        AnnotationIntrospector ai = new JaxbAnnotationIntrospector(mapper.getTypeFactory());
        mapper.setAnnotationIntrospector(ai);
        return mapper;
    }

    static {
        validSortColumns.add("createdDate");
        validSortColumns.add("createdBy");
        validSortColumns.add("updatedDate");
        validSortColumns.add("updatedBy");
        validSortColumns.add("deploymentDesc");
        validSortColumns.add("expirationDate");
        validSortColumns.add("marshalledTemplateData");
        validSortColumns.add("name");
        validSortColumns.add("health");
        validSortColumns.add("server");
    }

    public static final Set<String> validFilterColumns = new HashSet<>();

    static {
        validFilterColumns.add("id");
        validFilterColumns.add("createdDate");
        validFilterColumns.add("createdBy");
        validFilterColumns.add("updatedDate");
        validFilterColumns.add("updatedBy");
        validFilterColumns.add("deploymentDesc");
        validFilterColumns.add("expirationDate");
        validFilterColumns.add("marshalledTemplateData");
        validFilterColumns.add("name");
        validFilterColumns.add("health");
        validFilterColumns.add("server");
    }

    public static final Set<String> validPuppetLogFilterColumns = new HashSet<>();

    static {
        validPuppetLogFilterColumns.add("severity");
    }

    @Context
    private HttpServletResponse servletResponse;

    @Context
    private HttpServletRequest servletRequest;

    @Context
    private HttpHeaders httpHeaders;

    @Context
    private UriInfo uriInfo;

    private final DeploymentDAO deploymentDAO;
    private final DeploymentNamesRefDAO deploymentNamesRefDAO;
    private final DeviceInventoryDAO deviceInventoryDAO;
    private final DeviceInventoryComplianceDAO deviceInventoryComplianceDAO;
    private final ServiceTemplateUtil serviceTemplateUtil;
    private final GenericDAO genericDAO;
    private final ServiceTemplateDAO serviceTemplateDAO;
    private final AddOnModuleComponentsDAO addOnModuleComponentsDAO;
    private final FirmwareRepositoryDAO firmwareRepositoryDAO;
    private final BrownfieldUtil brownfieldUtil = BrownfieldUtil.getInstance();
    private final FirmwareUtil firmwareUtil;
    private final ServiceDeploymentUtil serviceDeploymentUtil;
    private MigrationDeviceUtils migrationDeviceUtils;

    // For Audit log message creation
    private LocalizableMessageService logService;

    private IPAddressPoolMgr ipAddressPoolMgr;
    private IOIdentityMgr ioIdentityMgr;

    private ServiceTemplateService serviceTemplateService;

    private NetworkingUtil networkingUtil;
    private ServerFilteringUtil filteringUtil;

    private IUserResource adminProxy;
    private IAsmDeployerService asmDeployerProxy;

    private DeviceGroupDAO deviceGroupDAO;
    private INetworkService networkService;

    private IJobManager jobManager;
    private ServiceTemplateValidator serviceTemplateValidator;
    private AsmManagerUtil asmManagerUtil;
    private DeploymentValidator deploymentValidator;

    // Constructor for testing with mocks
    public DeploymentService(DeploymentDAO deploymentDAO, DeviceInventoryDAO deviceInventoryDAO,
            DeviceInventoryComplianceDAO deviceInventoryComplianceDAO, ServiceTemplateUtil serviceTemplateUtil,
            LocalizableMessageService logService, IPAddressPoolMgr ipAddressPoolMgr, IOIdentityMgr ioIdentityMgr,
            INetworkService networkService, ServiceTemplateService serviceTemplateService, GenericDAO genericDAO,
            AddOnModuleComponentsDAO addOnModuleComponentsDAO, ServiceTemplateValidator validator,
            FirmwareUtil firmwareUtil, ServiceTemplateDAO serviceTemplateDAO,
            FirmwareRepositoryDAO firmwareRepositoryDAO, AsmManagerUtil asmManagerUtil,
            ServiceDeploymentUtil serviceDeploymentUtil, DeploymentValidator deploymentValidator,
            DeploymentNamesRefDAO deploymentNamesRefDAO) {
        this.deploymentDAO = deploymentDAO;
        this.deviceInventoryDAO = deviceInventoryDAO;
        this.deviceInventoryComplianceDAO = deviceInventoryComplianceDAO;
        this.serviceTemplateUtil = serviceTemplateUtil;
        this.logService = logService;
        this.ipAddressPoolMgr = ipAddressPoolMgr;
        this.ioIdentityMgr = ioIdentityMgr;
        this.genericDAO = genericDAO;
        this.addOnModuleComponentsDAO = addOnModuleComponentsDAO;
        this.networkingUtil = new NetworkingUtil(new PingUtil(), logService, new DnsUtil());
        this.serviceTemplateService = serviceTemplateService;
        this.brownfieldUtil.setDeviceInventoryDAO(this.deviceInventoryDAO);
        this.networkService = networkService;
        this.serviceTemplateValidator = validator;
        this.firmwareUtil = firmwareUtil;
        this.serviceTemplateDAO = serviceTemplateDAO;
        this.firmwareRepositoryDAO = firmwareRepositoryDAO;
        this.asmManagerUtil = asmManagerUtil;
        this.serviceDeploymentUtil = serviceDeploymentUtil;
        this.deploymentValidator = deploymentValidator;
        this.deploymentNamesRefDAO = deploymentNamesRefDAO;
    }

    public DeploymentService() {
        this(DeploymentDAO.getInstance(), new DeviceInventoryDAO(), DeviceInventoryComplianceDAO.getInstance(),
                new ServiceTemplateUtil(), LocalizableMessageService.getInstance(),
                (IPAddressPoolMgr) IPAddressPoolMgr.getInstance(), (IOIdentityMgr) IOIdentityMgr.getInstance(),
                ProxyUtil.getNetworkProxy(), new ServiceTemplateService(), GenericDAO.getInstance(),
                AddOnModuleComponentsDAO.getInstance(), new ServiceTemplateValidator(), new FirmwareUtil(),
                ServiceTemplateDAO.getInstance(), FirmwareRepositoryDAO.getInstance(), new AsmManagerUtil(),
                new ServiceDeploymentUtil(), DeploymentValidator.getInstance(), new DeploymentNamesRefDAO());

        setMigrationDeviceUtils(new MigrationDeviceUtils());
    }

    public IUserResource getAdminProxy() {
        if (adminProxy == null) {
            setAdminProxy(ProxyUtil.getAdminProxy());
        }
        return adminProxy;
    }

    public void setAdminProxy(IUserResource adminProxy) {
        this.adminProxy = adminProxy;
    }

    public IAsmDeployerService getAsmDeployerProxy() {
        if (asmDeployerProxy == null) {
            setAsmDeployerProxy(ProxyUtil.getAsmDeployerProxy());
        }
        return asmDeployerProxy;
    }

    public void setAsmDeployerProxy(IAsmDeployerService asmDeployerProxy) {
        this.asmDeployerProxy = asmDeployerProxy;
    }

    public DeviceGroupDAO getDeviceGroupDAO() {
        if (deviceGroupDAO == null) {
            setDeviceGroupDAO(DeviceGroupDAO.getInstance());
        }
        return deviceGroupDAO;
    }

    public void setDeviceGroupDAO(DeviceGroupDAO deviceGroupDAO) {
        this.deviceGroupDAO = deviceGroupDAO;
    }

    public IJobManager getJobManager() {
        if (jobManager == null) {
            setJobManager(JobManager.getInstance());
        }
        return jobManager;
    }

    public void setJobManager(IJobManager jobManager) {
        this.jobManager = jobManager;
    }

    public ServerFilteringUtil getFilteringUtil() {
        if (filteringUtil == null) {
            setFilteringUtil(new ServerFilteringUtil());
        }
        return filteringUtil;
    }

    public void setFilteringUtil(ServerFilteringUtil filteringUtil) {
        this.filteringUtil = filteringUtil;
    }

    public static void setProxyHeaders(Object ret, HttpServletRequest servletRequest) {
        if (servletRequest != null) {
            ProxyUtil.setProxyHeaders(ret, servletRequest);
        }
    }

    public void setServletRequest(HttpServletRequest servletRequest) {
        this.servletRequest = servletRequest;
    }

    @Override
    public Deployment getDeployment(String deploymentId) throws WebApplicationException {
        logger.debug("Get Deployment Entered for ID: " + deploymentId);
        Deployment deployment = null;
        if (DEFAULT_DEPLOYMENT_ID.equalsIgnoreCase(deploymentId)) // this helps in testing.
                                                                  // UI has no need for this.
        {
            deployment = new Deployment();
            ServiceTemplate svc = serviceTemplateService.getTemplate(DEFAULT_DEPLOYMENT_ID, false);
            deployment.setServiceTemplate(svc);
            deployment.setDeploymentName("Default Deployment");
            deployment.setId("1000");
            deployment.setCreatedBy("admin");
            deployment.setUpdatedBy("admin");
            return deployment;
        } else {
            try {
                DeploymentEntity deploymentEntity = deploymentDAO.getDeployment(deploymentId,
                        DeploymentDAO.DEVICE_INVENTORY_ENTITIES + DeploymentDAO.FIRMWARE_REPOSITORY_ENTITY);
                if (deploymentEntity == null) {
                    EEMILocalizableMessage msg = AsmManagerMessages.deploymentNotFound(deploymentId);
                    throw new LocalizedWebApplicationException(Response.Status.NOT_FOUND, msg);
                }
                User currentUser = this.asmManagerUtil.getCurrentUser(this.servletRequest);
                if (!checkUserPermissions(deploymentEntity, currentUser)) {
                    logger.debug("Refused access to deployment ID=" + deploymentId + " for user "
                            + asmManagerUtil.getUserId() + " because of lack of permissions");
                    throw new LocalizedWebApplicationException(Response.Status.NOT_FOUND,
                            AsmManagerMessages.deploymentNotFound(deploymentId));
                }

                deployment = entityToView(deploymentEntity, currentUser);

                if (StringUtils.isNotEmpty(deploymentEntity.getMarshalledTemplateData())) {
                    ServiceTemplate template = MarshalUtil.unmarshal(ServiceTemplate.class,
                            deploymentEntity.getMarshalledTemplateData());
                    deployment.setServiceTemplate(template);
                }
            } catch (LocalizedWebApplicationException e) {
                logger.error("LocalizedWebApplicationException while getting Deployment with ID " + deploymentId,
                        e);
                throw e;
            } catch (Exception e) {
                logger.error("Exception while getting Deployment with ID " + deploymentId, e);
                throw new LocalizedWebApplicationException(Response.Status.INTERNAL_SERVER_ERROR,
                        AsmManagerMessages.internalError());
            }
        }
        logger.debug("Get Deployment Finished for ID: " + deploymentId);
        ServiceTemplate serviceTemplate = deployment.getServiceTemplate();
        if (serviceTemplate != null) {
            ServiceTemplateUtil.stripPasswords(serviceTemplate, null);
        }
        return deployment;
    }

    @Override
    public Deployment[] getDeploymentsFromDeviceId(String deviceId) {
        logger.debug("Get Deployments for DeviceID: " + deviceId);
        List<Deployment> deployments = new ArrayList<Deployment>();
        DeviceInventoryEntity deviceInventoryEntity = deviceInventoryDAO.getDeviceInventory(deviceId);
        User currentUser = this.asmManagerUtil.getCurrentUser(this.servletRequest);
        if (deviceInventoryEntity != null && deviceInventoryEntity.getDeployments() != null) {
            List<DeploymentEntity> deploymentEntities = deviceInventoryEntity.getDeployments();
            if (deploymentEntities != null) {
                for (DeploymentEntity entity : deploymentEntities) {
                    if (checkUserPermissions(entity, currentUser)) { // Only let the user view it if they have access
                        Deployment deployment = entityToView(entity);
                        deployments.add(deployment);
                    }
                }
            }
        }
        return deployments.toArray(new Deployment[deployments.size()]);
    }

    @Override
    public Deployment[] getDeployments(String sort, List<String> filter, Integer offset, Integer limit,
            Boolean fullTemplates) {

        List<Deployment> deployments = new ArrayList<>();

        // Parse the sort parameter.
        // Any sort exceptions are already encased in a WebApplicationException with an Status code=400
        SortParamParser sp = new SortParamParser(sort, validSortColumns);
        List<SortParamParser.SortInfo> sortInfos = sp.parse();

        // Build filter list from filter params ( comprehensive )
        FilterParamParser filterParser = new FilterParamParser(filter, validFilterColumns);
        List<FilterParamParser.FilterInfo> filterInfos = filterParser.parse();

        PaginationParamParser paginationParamParser = new PaginationParamParser(servletRequest, servletResponse,
                httpHeaders, uriInfo);

        int pageOffSet;
        if (offset == null) {
            pageOffSet = 0;
        } else {
            pageOffSet = offset;
        }

        int totalRecords = 0;
        int pageLimit;
        if (limit == null) {
            pageLimit = paginationParamParser.getMaxLimit();
        } else {
            pageLimit = limit;
        }

        List<DeploymentEntity> entities = deploymentDAO.getAllDeployments(sortInfos, filterInfos, null,
                DeploymentDAO.DEVICE_INVENTORY_ENTITIES + DeploymentDAO.FIRMWARE_REPOSITORY_ENTITY);

        if (entities != null) {
            if (pageLimit <= 0) {
                pageLimit = entities.size();
            }
            int index = 0;
            int startIndex = pageOffSet * pageLimit;
            int endIndex = startIndex + pageLimit;

            User currentUser = this.asmManagerUtil.getCurrentUser(this.servletRequest);
            for (DeploymentEntity entity : entities) {
                if (checkUserPermissions(entity, currentUser)) {
                    totalRecords++;
                    if (index >= startIndex && index <= endIndex) {
                        Deployment deployment = new Deployment();

                        deployment.setId(entity.getId());
                        deployment.setDeploymentName(entity.getName());
                        deployment.setDeploymentDescription(entity.getDeploymentDesc());
                        deployment.setCreatedDate(entity.getCreatedDate());
                        deployment.setCreatedBy(entity.getCreatedBy());
                        deployment.setUpdatedDate(entity.getUpdatedDate());
                        deployment.setUpdatedBy(entity.getUpdatedBy());
                        deployment.setStatus(entity.getStatus());
                        deployment.setCompliant(entity.isCompliant());
                        deployment.setUpdateServerFirmware(entity.isManageFirmware());
                        deployment.setUseDefaultCatalog(entity.isUseDefaultCatalog());

                        FirmwareRepositoryEntity repoEntity = entity.getFirmwareRepositoryEntity();
                        if (repoEntity != null) {
                            deployment.setFirmwareRepositoryId(repoEntity.getId());
                            deployment.setFirmwareRepository(repoEntity.getSimpleFirmwareRepository());
                        }

                        // need service template
                        if (StringUtils.isNotEmpty(entity.getMarshalledTemplateData())) {
                            ServiceTemplate template = MarshalUtil.unmarshal(ServiceTemplate.class,
                                    entity.getMarshalledTemplateData());
                            Map<String, DeviceInventoryEntity> devicesMap = new HashMap<>();
                            for (DeviceInventoryEntity device : entity.getDeployedDevices()) {
                                devicesMap.put(device.getRefId(), device);
                            }
                            // strip heavy weighted items
                            for (ServiceTemplateComponent component : template.getComponents()) {
                                DeviceInventoryEntity deviceEntity = devicesMap.get(component.getAsmGUID());
                                if (deviceEntity != null) {
                                    DeploymentDevice newDevice = new DeploymentDevice();
                                    newDevice.setRefId(deviceEntity.getRefId());
                                    newDevice.setIpAddress(deviceEntity.getIpAddress());
                                    newDevice.setServiceTag(deviceEntity.getServiceTag());
                                    newDevice.setDeviceType(deviceEntity.getDeviceType());
                                    newDevice.setDeviceHealth(deviceEntity.getHealth());
                                    newDevice.setHealthMessage(deviceEntity.getHealthMessage());
                                    newDevice.setCompliantState(this.getCompliantState(entity, deviceEntity));

                                    if (!CompliantState.COMPLIANT.equals(newDevice.getCompliantState())) {
                                        deployment.setCompliant(false);
                                    }
                                    deployment.getDeploymentDevice().add(newDevice);
                                }

                                if (component.getResources() != null && !fullTemplates) {
                                    component.getResources().clear();
                                }

                            }
                            deployment.setServiceTemplate(template);

                        }
                        deployment.setDeploymentHealthStatusType(
                                this.calculateDeploymentHealthStatusType(deployment));

                        deployments.add(deployment);
                    }
                    index++;
                }
            }
        }

        if (httpHeaders != null) {
            UriBuilder linkBuilder = RestUtil.getProxyBaseURIBuilder(uriInfo, servletRequest, httpHeaders);

            linkBuilder.replaceQuery(null);
            linkBuilder.path("device");
            if (sort != null) {
                linkBuilder.queryParam(AsmConstants.QUERY_PARAM_SORT, sort);
            }

            if (filterInfos != null) {
                for (FilterParamParser.FilterInfo filterInfo : filterInfos) {
                    if (filterInfo.isSimpleFilter()) {
                        // Simple filter take only one value.
                        linkBuilder.queryParam(filterInfo.getColumnName(), filterInfo.buildValueString());
                    } else {
                        linkBuilder.queryParam(AsmConstants.QUERY_PARAM_FILTER, filterInfo.buildValueString());
                    }
                }
            }

            PaginationParamParser.PaginationInfo paginationInfo = paginationParamParser.new PaginationInfo(
                    pageOffSet, pageLimit, totalRecords);
            // Common library to add link headers in response headers
            paginationParamParser.addLinkHeaders(paginationInfo, linkBuilder);

            servletResponse.setHeader(AsmConstants.DELL_TOTAL_COUNT_HEADER, String.valueOf(totalRecords));
        }
        return deployments.toArray(new Deployment[deployments.size()]);
    }

    public Deployment entityToView(DeploymentEntity deploymentEntity) {
        User currentUser = this.asmManagerUtil.getCurrentUser(this.servletRequest);
        return this.entityToView(deploymentEntity, currentUser);
    }

    private Deployment entityToView(DeploymentEntity deploymentEntity, User thisUser) {
        logger.debug("entityToView " + deploymentEntity.getId() + " " + deploymentEntity.getJobId());
        Deployment deployment = new Deployment();
        deployment.setId(deploymentEntity.getId());
        deployment.setBrownfield(deploymentEntity.isBrownfield());
        deployment.setCreatedBy(deploymentEntity.getCreatedBy());
        deployment.setUpdateServerFirmware(deploymentEntity.isManageFirmware());
        deployment.setUseDefaultCatalog(deploymentEntity.isUseDefaultCatalog());

        if (Hibernate.isInitialized(deploymentEntity.getFirmwareRepositoryEntity())) {
            FirmwareRepositoryEntity repoEntity = deploymentEntity.getFirmwareRepositoryEntity();
            if (repoEntity != null) {
                deployment.setFirmwareRepositoryId(repoEntity.getId());
                deployment.setFirmwareRepository(repoEntity.getSimpleFirmwareRepository());
            }
        }

        deployment.setDeploymentName(deploymentEntity.getName());
        deployment.setDeploymentDescription(deploymentEntity.getDeploymentDesc());

        deployment.setCreatedDate(deploymentEntity.getCreatedDate());
        deployment.setCreatedBy(deploymentEntity.getCreatedBy());
        deployment.setUpdatedDate(deploymentEntity.getUpdatedDate());
        deployment.setUpdatedBy(deploymentEntity.getUpdatedBy());

        deployment.setDeploymentStartedDate(deploymentEntity.getDeploymentStartedDate());
        deployment.setDeploymentFinishedDate(deploymentEntity.getDeploymentFinishedDate());

        boolean powerUser = false;
        if (thisUser == null) {
            // Normally shouldn't be allowed to not have a valid user, but there is no harm in this
            // case as it just changes some of the return values and it makes testing easier.
            powerUser = false;
        } else {
            boolean isAdmin = thisUser.getRole().equals(AsmConstants.USERROLE_ADMINISTRATOR);
            boolean isOwner = thisUser.getUserName().equals(deploymentEntity.getCreatedBy());
            powerUser = isAdmin || isOwner;
        }
        deployment.setOwner(deploymentEntity.getCreatedBy());

        deployment.setCanCancel(powerUser);
        deployment.setCanDelete(powerUser);
        deployment.setCanEdit(powerUser);
        deployment.setCanRetry(powerUser);
        deployment.setCanDeleteResources(powerUser);

        deployment.setCanMigrate(false);
        deployment.setCanScaleupServer(powerUser);
        deployment.setCanScaleupStorage(powerUser);
        deployment.setCanScaleupVM(powerUser);
        deployment.setCanScaleupApplication(powerUser);
        deployment.setCanScaleupCluster(false);
        deployment.setCanScaleupNetwork(powerUser);

        deployment.setAllUsersAllowed(deploymentEntity.isAllUsersAllowed());
        deployment.setAssignedUsers(new HashSet<User>());

        deployment.setTemplateValid(deploymentEntity.isTemplateValid());
        deployment.setStatus(deploymentEntity.getStatus());
        deployment.setCompliant(deploymentEntity.isCompliant());

        if (deploymentEntity.getAssignedUserList() != null) {
            for (DeploymentUserRefEntity ref : deploymentEntity.getAssignedUserList()) {
                try {
                    User user = getAdminProxy().getUser(ref.getUserId());
                    deployment.getAssignedUsers().add(user);
                } catch (LocalizedWebApplicationException lwae) {
                    logger.warn(
                            "Could not find User in the Users database for user sequence id: " + ref.getUserId(),
                            lwae);
                }
            }
        }

        if (deploymentEntity.getVmList() != null && deploymentEntity.getVmList().size() > 0) {
            deployment.setVms(new HashSet<VM>());
            for (VMRefEntity currDevice : deploymentEntity.getVmList()) {
                VM newVm = new VM();
                newVm.setCertificateName(currDevice.getVmId());
                newVm.setVmIpaddress(currDevice.getVmIpaddress());
                newVm.setVmManufacturer(currDevice.getVmManufacturer());
                newVm.setVmModel(currDevice.getVmModel());
                newVm.setVmServiceTag(currDevice.getVmServiceTag());
                deployment.getVms().add(newVm);
            }
        }

        ServiceTemplate template = MarshalUtil.unmarshal(ServiceTemplate.class,
                deploymentEntity.getMarshalledTemplateData());
        deployment.setServiceTemplate(template);

        // get the status of this job from Ruby service ( i.e. asm-deployer )
        List<AsmDeployerComponentStatus> asmDeployerComponentStatuses = null;

        // If status is pending, deployment has not yet been sent to asm-deployer
        if (DeploymentStatusType.PENDING != deployment.getStatus()) {
            try {
                AsmDeployerStatus dStatus = getAsmDeployerProxy().getDeploymentStatus(deploymentEntity.getId());
                // do not update DB record with this status, as it can be different because of components/firmware compliance
                asmDeployerComponentStatuses = dStatus.getComponents();
            } catch (WebApplicationException e) {
                logger.error("Failed to retrieve deployment " + deploymentEntity.getId() + " status", e);
            }
        }

        if (Hibernate.isInitialized(deploymentEntity.getDeployedDevices())) {

            //Check if any of the associated inventory is currently having its firmware updated
            if (deployment.getStatus() == DeploymentStatusType.COMPLETE) {
                for (DeviceInventoryEntity device : deploymentEntity.getDeployedDevices()) {
                    if (device.getState() == DeviceState.UPDATING) {
                        deployment.setStatus(DeploymentStatusType.IN_PROGRESS);
                        break;
                    }
                }
            }

            if (asmDeployerComponentStatuses != null) {
                deployment.setDeploymentDevice(new HashSet<DeploymentDevice>());
                deployment.setCompliant(deploymentEntity.isCompliant());

                for (AsmDeployerComponentStatus cs : asmDeployerComponentStatuses) {
                    DeploymentDevice newDevice = new DeploymentDevice();
                    newDevice.setRefId(cs.getAsmGuid());
                    newDevice.setRefType(cs.getType().name());
                    newDevice.setComponentId(cs.getId());
                    newDevice.setStatus(cs.getStatus());
                    newDevice.setStatusMessage(cs.getMessage());
                    newDevice.setStatusStartTime(cs.getStartTime());
                    newDevice.setStatusEndTime(cs.getEndTime());

                    // need some data from inventory but don't want to make expensive call to DAO
                    for (DeviceInventoryEntity device : deploymentEntity.getDeployedDevices()) {
                        if (device.getRefId().equals(cs.getAsmGuid())) {
                            newDevice.setIpAddress(device.getIpAddress());
                            newDevice.setServiceTag(device.getServiceTag());
                            newDevice.setDeviceType(device.getDeviceType());
                            newDevice.setDeviceHealth(device.getHealth());
                            newDevice.setHealthMessage(device.getHealthMessage());
                            newDevice.setCompliantState(this.getCompliantState(deploymentEntity, device));

                            if (!CompliantState.COMPLIANT.equals(newDevice.getCompliantState())) {
                                deployment.setCompliant(false);
                            }
                        }
                    }

                    ServiceTemplateComponent templateComponent = (template == null) ? null
                            : template.findComponentById(cs.getId());

                    if (templateComponent != null) {
                        deployment.getDeploymentDevice().add(newDevice);

                        if (ServiceTemplateComponentType.SERVER.equals(cs.getType())) {
                            // Service can migrate if at least one device can migrate.
                            // Service can scale up servers in all cases, we now support scaleUp from scratch. Except Boot from SAN
                            // service can scale up storage if it is not HyperV swim lane and Not Boot from SAN
                            if (templateComponent.hasSanBoot()) {
                                deployment.setCanMigrate(powerUser);
                                deployment.setCanScaleupStorage(false);
                                deployment.setCanScaleupServer(false);
                            }
                            deployment.setVDS(ServiceDeploymentUtil.isVDSService(template, templateComponent));
                        }
                    }
                }
            } else { // null possibly due to Pending status
                if (DeploymentStatusType.PENDING == deployment.getStatus()) {
                    Set<DeviceInventoryEntity> deviceInventoryEntities = deploymentEntity.getDeployedDevices();
                    ArrayList<AsmDeployerComponentStatus> fakeAsmDeployerComponentStatuses = new ArrayList<AsmDeployerComponentStatus>();

                    for (DeviceInventoryEntity deviceInventoryEntity : deviceInventoryEntities) {
                        DeploymentDevice newDevice = new DeploymentDevice();
                        newDevice.setRefId(deviceInventoryEntity.getRefId());
                        newDevice.setStatus(DeploymentStatusType.PENDING); // Set to Pending since they are scheduled/pending
                        newDevice.setIpAddress(deviceInventoryEntity.getIpAddress());
                        newDevice.setServiceTag(deviceInventoryEntity.getServiceTag());
                        newDevice.setDeviceType(deviceInventoryEntity.getDeviceType());
                        newDevice.setDeviceHealth(deviceInventoryEntity.getHealth());
                        newDevice.setHealthMessage(deviceInventoryEntity.getHealthMessage());
                        newDevice.setCompliantState(CompliantState.fromValue(deviceInventoryEntity.getCompliant()));

                        ServiceTemplateComponent templateComponent = (template == null) ? null
                                : template.findComponentByGUID(deviceInventoryEntity.getRefId());

                        // newDevice.setStatusEndTime(statusEndTime);
                        // newDevice.setStatusMessage(statusMessage);
                        // newDevice.setStatusStartTime(statusStartTime);

                        if (templateComponent != null) {
                            newDevice.setComponentId(templateComponent.getId());
                            newDevice.setRefType(templateComponent.getType().name());
                            deployment.getDeploymentDevice().add(newDevice);

                            if (ServiceTemplateComponentType.SERVER.equals(templateComponent.getType())) {
                                // find corresponding device
                                // Service can migrate if at least one device can migrate.
                                // Service can scale up servers in all cases, we now support scaleUp from scratch. Except Boot from SAN
                                // service can scale up storage if it is not HyperV swim lane and Not Boot from SAN
                                if (templateComponent.hasSanBoot()) {
                                    deployment.setCanMigrate(powerUser);
                                    deployment.setCanScaleupStorage(false);
                                    deployment.setCanScaleupServer(false);
                                }

                            }
                        }
                    }
                }
            }
        }

        // get the detailed logs for this job from Ruby service ( i.e. asm-deployer )
        try {
            List<AsmDeployerLogEntry> dLogs = getAsmDeployerProxy().getDeploymentLogs(deploymentEntity.getId());
            deployment.setJobDetails(dLogs);
        } catch (Exception logErr) {
            logger.warn("asm-deployer log service returned exception", logErr);
        }

        deployment.setDeploymentHealthStatusType(this.calculateDeploymentHealthStatusType(deployment));

        return deployment;
    }

    @Override
    public List<PuppetLogEntry> getPuppetLogs(String deploymentId, String certName, List<String> filter) {

        // Ensure the User has access to the deployment information
        this.checkUserPermission(deploymentId);

        // Return the Puppet Logs
        FilterParamParser filterParser = new FilterParamParser(filter, validPuppetLogFilterColumns);
        final List<FilterParamParser.FilterInfo> filterInfos = filterParser.parse();

        List<PuppetLogEntry> puppetLogs = getAsmDeployerProxy().getAsmPuppetLogs(deploymentId, certName);
        CollectionUtils.filter(puppetLogs, new Predicate() {
            public boolean evaluate(Object input) {
                if (CollectionUtils.isEmpty(filterInfos))
                    return true;
                if (!(input instanceof PuppetLogEntry))
                    return false;

                PuppetLogEntry entry = (PuppetLogEntry) input;
                for (FilterParamParser.FilterInfo filter : filterInfos) {
                    // only care about severity at this time
                    if (filter.getColumnName().equals(SEVERITY_COLUMN)) {
                        if (CollectionUtils.isNotEmpty(filter.getColumnValue())) {
                            return filter.getColumnValue().contains(entry.getSeverity());
                        } else {
                            return true; // any ?
                        }
                    }
                }
                logger.debug("no category column? filtering out puppet log record:" + entry.toString());
                return false;
            }
        });
        return puppetLogs;
    }

    /**
     * Utility method because we need to do this same operation for both a new deployment and do the same thing to an 
     * updated servicetemplate on adjust service call to add new resources.
     * 
     * @param serviceTemplate
     * @param deploymentEntity
     * @param  selectedServers
     * @throws LocalizedWebApplicationException
     */
    private List<SelectedServer> updateFromComponentValues(ServiceTemplate serviceTemplate,
            DeploymentEntity deploymentEntity, List<SelectedServer> selectedServers,
            List<ServiceTemplateComponent> newComponents) throws LocalizedWebApplicationException {
        Map<String, Set<String>> serverRefIdsToComponentsMap = new HashMap<>();
        Map<String, DeviceInventoryEntity> serverInventoryCache = new HashMap<>();
        List<SelectedServer> processedServers = new ArrayList<>();

        try {
            for (ServiceTemplateComponent component : serviceTemplate.getComponents()) {

                //Used if we are updating a service template and only want to touch newly added components
                if (newComponents != null) {
                    boolean isNew = false;
                    for (ServiceTemplateComponent comp : newComponents) {
                        if (comp.getId().equals(component.getId()))
                            isNew = true;
                    }
                    if (!isNew) {
                        if (ServiceTemplateComponentType.SERVER.equals(component.getType())) {
                            String refId = component.getAsmGUID();
                            if (refId == null) {
                                logger.error("Pre-existing server component does not have a ref id: "
                                        + component.getName() + ", " + component);
                            } else {
                                Set<String> componentNames = serverRefIdsToComponentsMap
                                        .get(component.getAsmGUID());
                                if (componentNames == null) {
                                    componentNames = new HashSet<>();
                                    serverRefIdsToComponentsMap.put(component.getAsmGUID(), componentNames);
                                }
                                componentNames.add(component.getName());
                            }
                        }
                        continue;
                    }
                }

                String puppetCertName = null;
                for (ServiceTemplateCategory resource : component.getResources()) {
                    Iterator<ServiceTemplateSetting> iterator = resource.getParameters().iterator();
                    while (iterator.hasNext()) {
                        ServiceTemplateSetting param = iterator.next();
                        logger.trace("Resource: " + resource.getId() + " parameter: " + param.getId());

                        if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ASM_GUID.equals(param.getId())) {
                            DeviceInventoryEntity theDevice = deviceInventoryDAO
                                    .getDeviceInventory(param.getValue());

                            if (theDevice == null || theDevice.getDeviceType() == null
                                    || theDevice.getServiceTag() == null) {
                                throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                                        AsmManagerMessages.missingDeviceInfo(serviceTemplate.getTemplateName(),
                                                component.getType().toString()));
                            }

                            deploymentEntity.getDeployedDevices().add(theDevice);

                            if (DeviceType.isServer(theDevice.getDeviceType())) {
                                deviceInventoryDAO.setDeviceState(theDevice,
                                        DeviceState.fromDeploymentStatusType(deploymentEntity.getStatus()), true);
                            }

                            component.setAsmGUID(param.getValue());
                            puppetCertName = PuppetModuleUtil.toCertificateName(theDevice);

                        } else {
                            if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_SOURCE.equals(param.getId())) {
                                DeviceInventoryEntity server = null;
                                SelectedServer selectedServer = null;

                                if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_SOURCE_POOL
                                        .equals(param.getValue())) {
                                    ServiceTemplateSetting poolParam = resource.getParameter(
                                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_POOL_ID);

                                    Iterator<SelectedServer> ssI = selectedServers.iterator();
                                    while (ssI.hasNext()) {
                                        SelectedServer ss = ssI.next();
                                        if (ss.getComponentId().equals(component.getId())) {
                                            server = deviceInventoryDAO.getDeviceInventory(ss.getRefId());
                                            processedServers.add(ss);
                                            selectedServer = ss;
                                            ssI.remove(); // must remove so we don't take it again next time, in case we have multiple service instances
                                            break;
                                        }
                                    }
                                } else if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_SOURCE_MANUAL
                                        .equals(param.getValue())) {
                                    ServiceTemplateSetting serverParam = resource.getParameter(
                                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_MANUAL_SELECTION);
                                    server = deviceInventoryDAO.getDeviceInventory(serverParam.getValue());

                                    Iterator<SelectedServer> ssI = selectedServers.iterator();
                                    while (ssI.hasNext()) {
                                        SelectedServer ss = ssI.next();
                                        if (ss.getRefId().equals(server.getRefId())) {
                                            processedServers.add(ss);
                                            selectedServer = ss;
                                            ssI.remove(); // must remove so we don't take it again next time, in case we have multiple service instances
                                            break;
                                        }
                                    }
                                }

                                if (server == null) {
                                    // ups. something got wrong, we should have exact match for selected servers and components
                                    throw new LocalizedWebApplicationException(
                                            Response.Status.INTERNAL_SERVER_ERROR,
                                            AsmManagerMessages.internalError());
                                }

                                deploymentEntity.getDeployedDevices().add(server);

                                if (DeviceType.isServer(server.getDeviceType())) {
                                    deviceInventoryDAO.setDeviceState(server,
                                            DeviceState.fromDeploymentStatusType(deploymentEntity.getStatus()),
                                            true);
                                }

                                component.setAsmGUID(server.getRefId());
                                addNICsToNetworkConfiguration(component, selectedServer, false);
                                puppetCertName = PuppetModuleUtil.toCertificateName(server);

                                Set<String> componentNames = serverRefIdsToComponentsMap.get(server.getRefId());
                                if (componentNames == null) {
                                    componentNames = new HashSet<>();
                                    serverRefIdsToComponentsMap.put(server.getRefId(), componentNames);
                                }
                                componentNames.add(component.getName());
                                serverInventoryCache.put(server.getRefId(), server);
                            } else if (ServiceTemplateUtil.isConfirmPassword(param.getId())) {
                                // Remove confirm password fields before passing to backend
                                iterator.remove();
                            }
                        }
                    }

                }

                if (puppetCertName != null) {
                    component.setPuppetCertName(puppetCertName);
                } else if (StringUtils.isEmpty(component.getPuppetCertName())) {
                    // Some cases do not have cert names, such as the case of an application
                    // component attached to multiple VMs or servers.
                    component.setPuppetCertName(component.getId());
                }
            }
            // Ensure duplicate servers haven't been specified
            for (Map.Entry<String, Set<String>> entry : serverRefIdsToComponentsMap.entrySet()) {
                Set<String> componentNames = entry.getValue();
                if (componentNames.size() > 1) {
                    String refId = entry.getKey();
                    DeviceInventoryEntity serverInventory = serverInventoryCache.get(refId);
                    if (serverInventory == null) {
                        serverInventory = deviceInventoryDAO.getDeviceInventory(refId);
                    }
                    throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST, AsmManagerMessages
                            .duplicateServersChosen(componentNames, serverInventory.getServiceTag()));
                }
            }

            return processedServers;
        } catch (LocalizedWebApplicationException lwe) {
            // rollback attached servers
            logger.error("Device Resevation for deployment " + deploymentEntity.getId()
                    + " failed. Rolling back attached devices and their states");
            for (DeviceInventoryEntity theDevice : deploymentEntity.getDeployedDevices()) {
                if (DeviceType.isServer(theDevice.getDeviceType())) {
                    deviceInventoryDAO.setDeviceState(theDevice, DeviceState.READY, true);
                }
            }
            deploymentEntity.getDeployedDevices().clear();
            throw lwe;
        }
    }

    /**
     * This will add list of FQDDs from SelectedServer to NetworkConfiguration
     * @param component
     * @param selectedServer
     */
    private void addNICsToNetworkConfiguration(ServiceTemplateComponent component, SelectedServer selectedServer,
            boolean isMigrate) {

        if (selectedServer.getNics() == null)
            return;

        if (component.getType() == ServiceTemplateComponentType.SERVER) {
            for (ServiceTemplateCategory resource : component.getResources()) {
                ServiceTemplateSetting networkingSetting = resource
                        .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_NETWORK_CONFIG_ID);
                if (networkingSetting != null) {
                    com.dell.asm.asmcore.asmmanager.client.networkconfiguration.NetworkConfiguration networkConfig = null;
                    if (isMigrate) {
                        networkConfig = networkingSetting.getNetworkConfiguration();
                    } else {
                        networkConfig = ServiceTemplateUtil.deserializeNetwork(networkingSetting.getValue());
                    }

                    if (networkConfig != null && networkConfig.getInterfaces() != null) {

                        for (Fabric f : networkConfig.getInterfaces()) {
                            for (SelectedNIC nic : selectedServer.getNics()) {
                                int portNumNic = nic.getPortNumber();
                                if (f.getId().equals(nic.getId())) {
                                    for (Interface ifc : f.getInterfaces()) {
                                        String[] ikeys = ifc.getName().split(" ");
                                        if (ikeys.length > 1) {
                                            try {
                                                int portNum = Integer.parseInt(ikeys[1]);
                                                if (portNum == portNumNic) {
                                                    ifc.setFqdd(nic.getFqdd());
                                                }
                                            } catch (NumberFormatException e) {
                                                logger.warn("Bad name for interface: " + ifc.getName()
                                                        + ". Cannot set fqdd.");
                                            }
                                        } else {
                                            logger.warn("Bad name for interface: " + ifc.getName()
                                                    + ". Cannot set fqdd.");
                                        }
                                    }
                                }
                            }
                        }
                        String json = ServiceTemplateUtil.serializeNetwork(networkConfig);
                        networkingSetting.setValue(json);

                    }

                } else {
                    logger.debug("Cannot set FQDDS in template: NetworkConfiguration not found on server component "
                            + component.getId());
                }
            }
        }
    }

    /**
     * Marshal deployment to JSON. Note that this method is used instead of
     * MarshalUtil.toJSON because that method uses the jettison JSON library
     * which has some quirks such as rendering single-element lists as just
     * the element, rather than a list of one element. This method uses
     * the jackson library which is also used by the TomEE container for
     * marshalling JAX-RS calls and does not have that quirk.
     *
     * At some point MarshalUtil should be changed to use jackson and this
     * could be removed.
     *
     * @param deployment The deployment object to marshal
     * @return The JSON-formatted deployment
     */
    public static String toJson(Deployment deployment) {
        try {
            StringWriter sw = new StringWriter();
            OBJECT_MAPPER.writeValue(sw, deployment);
            return sw.toString();
        } catch (IOException e) {
            throw new AsmManagerRuntimeException("Failed to marshal deployment", e);
        }
    }

    /**
     * Unmarshal deployment json data. This is used instead of
     * MarshalUtil.fromJSON because that method uses the jettison JSON library
     * which may not be able to parse the JSON generated by
     * {@link #toJson(com.dell.asm.asmcore.asmmanager.client.deployment.Deployment)}
     * which uses the jackson library. See that method for more details on why
     * that is used.
     *
     * @param json The json text
     * @return The deployment object
     */
    public static Deployment fromJson(String json) {
        try {
            return OBJECT_MAPPER.readValue(json, Deployment.class);
        } catch (IOException e) {
            throw new AsmManagerRuntimeException("Failed to unmarshal deployment json", e);
        }
    }

    /**
     * Create a Deployment, persist it to the database and initiate a deployment job which invokes asm-deployer on the back-end via a REST service.
     * 
     * <p>
     * The deployment contains a ServiceTemplate. The ServiceTemplate should have been created via ServiceTemplateService and will be persisted.
     * However, the deployment template may contain values that are not identical to the values contained in the persisted template. This is the case
     * when the user enters parameter values at deployment time. As such, the template needs to be re-validated.
     * 
     * @param deployment
     *            The deployment data
     * @return The deployment data including its assigned id
     * @throws WebApplicationException
     *             If any error occurs
     */
    @Override
    public Deployment createDeployment(Deployment deployment) throws WebApplicationException {
        logger.info("Entering createDeployment(Deployment)");

        // Validation
        ServiceTemplate serviceTemplate = deployment.getServiceTemplate();
        if (serviceTemplate == null || serviceTemplate.getId() == null) {
            logger.error("No Service Template found.");
            throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                    AsmManagerMessages.noServiceTemplateFoundForDeployment());
        }

        ServiceTemplateEntity templateById = serviceTemplateDAO.getTemplateById(serviceTemplate.getId());
        String templateName = "brownfield";

        if (!deployment.isBrownfield()) {
            templateName = templateById.getName();
        } else { // It is brownfield so remove components not in inventory as a precaution
            deployment = brownfieldUtil.getDeploymentWithOnlyDevicesInInventory(deployment);
            if (!deployment.getServiceTemplate()
                    .containsServiceTemplateComponentOfType(ServiceTemplateComponentType.SERVER)) {
                logger.warn("Create deployment failed as there are no servers available for "
                        + deployment.getDeploymentName());
                throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                        AsmManagerMessages.noServersAvailableForDeployment(deployment.getDeploymentName()));
            }
        }

        if (!deployment.isBrownfield() && templateById == null) {
            logger.error("No Service Template found for id " + templateById + ".");
            throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                    AsmManagerMessages.noServiceTemplateFoundForDeployment());
        }

        DeploymentEntity duplicateCheck = deploymentDAO.getDeploymentByName(deployment.getDeploymentName(),
                DeploymentDAO.NONE);
        if (duplicateCheck != null) {
            logger.warn(
                    "Create deployment failed, the name " + deployment.getDeploymentName() + " is already in use.");
            throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                    AsmManagerMessages.renameToDuplicateName(deployment.getDeploymentName()));
        }

        DeploymentValid deploymentValid = deploymentValidator.validateDeployment(deployment, false);
        if (!deploymentValid.isValid()) {
            logger.error("Validation failed for create Deployment");
            throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                    new AsmDetailedMessageList(deploymentValid.getMessages()));
        }

        String deploymentId = null;
        DeploymentEntity deploymentEntity = null;

        try {
            if (!deployment.isBrownfield()) {
                // Replace the passed service template with one from db. The passed template
                // may not contain password values.
                String xmlBlob = templateById.getMarshalledTemplateData();
                ServiceTemplate origTemplate = MarshalUtil.unmarshal(ServiceTemplate.class, xmlBlob);

                // Copy passwords with new ids so that if the service template gets deleted
                // we still have copies
                serviceTemplateUtil.duplicatePasswords(origTemplate);

                // Populate deployment template with passwords from the original template and encrypt
                // any new passwords passed into the deployment template
                serviceTemplateUtil.encryptPasswords(serviceTemplate, origTemplate);

                // Delete out any passwords that may have been overwritten by changes in serviceTemplate
                serviceTemplateUtil.deleteRemovedEncryptionIds(origTemplate, serviceTemplate);

                GregorianCalendar now = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
                templateById.setLastDeployedDate(now);
                serviceTemplateDAO.updateTemplate(templateById);

                // Build copy of service template to decrypt the passwords in and use for validation.
                // Otherwise validation against passwords may fail.
                String tempXml = MarshalUtil.marshal(serviceTemplate);
                ServiceTemplate templateToValidate = MarshalUtil.unmarshal(ServiceTemplate.class, tempXml);
                serviceTemplateUtil.decryptPasswords(templateToValidate);

                // to update template options with latest values from inventory
                ServiceTemplateService.fillMissingParams(serviceTemplateService.getDefaultTemplate(),
                        templateToValidate);

                serviceTemplateValidator.validateTemplate(templateToValidate,
                        new ServiceTemplateValidator.ValidationOptions(true, true, true));
                if (!templateToValidate.getTemplateValid().isValid()) {
                    throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                            serviceTemplateValidator.getAllServiceTemplateValidationMessages(templateToValidate));
                }
            }

            JobDetail job = null;
            String jobName = "";
            SimpleScheduleBuilder schedBuilder = SimpleScheduleBuilder.simpleSchedule();

            int dIx = 1;
            String originalName = deployment.getDeploymentName();
            String origDeploymentXml = MarshalUtil.marshal(deployment);
            Deployment firstDeployment = deployment;
            Date scheduleDate = deployment.getScheduleDate();

            DeploymentFilterResponse filterResponse = null;
            List<SelectedServer> selectedServers = new ArrayList<>();
            if (!deployment.isBrownfield()) {
                filterResponse = filterAvailableServers(serviceTemplate, deployment.getNumberOfDeployments(), true);
                if (filterResponse.getNumberRequestedServers() > filterResponse.getNumberSelectedServers()) {
                    Map<String, String> rejectServersReason = new HashMap<String, String>();
                    sortRejectServerResponse(rejectServersReason, filterResponse.getRejectedServers(),
                            filterResponse.getNumberSelectedServers());
                    throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                            AsmManagerMessages.serverRejectForDeployment(rejectServersReason));
                }

                // the list of servers for RAID configuration. The list will be modified: one server taken for each deployment instance
                selectedServers.addAll(filterResponse.getSelectedServers());
            } else {
                selectedServers.addAll(brownfieldUtil.getSelectedServersForBrownfield(serviceTemplate));
            }

            for (int i = 0; i < deployment.getNumberOfDeployments(); i++) {
                deploymentId = null; // reset or possible exception will delete wrong deployment
                deploymentEntity = null;

                if (i > 0) {
                    String nextName = originalName + " (" + dIx + ")";
                    duplicateCheck = deploymentDAO.getDeploymentByName(nextName, DeploymentDAO.NONE);
                    while (duplicateCheck != null) {
                        dIx++;
                        nextName = originalName + " (" + dIx + ")";
                        duplicateCheck = deploymentDAO.getDeploymentByName(nextName, DeploymentDAO.NONE);
                    }

                    // Ensure that each deployment is a unique object so that methods below (such
                    // as ensureResourceHasTitle) won't impact subsequent deployments
                    deployment = MarshalUtil.unmarshal(Deployment.class, origDeploymentXml);
                    serviceTemplate = deployment.getServiceTemplate();
                    deployment.setDeploymentName(nextName);

                    // Subsequent deployments should be staggered.
                    int staggerSecs = AsmManagerApp.getMultiDeploymentsStaggerSecs();
                    if (staggerSecs > 0) {
                        if (scheduleDate == null) {
                            scheduleDate = new Date();
                        }
                        scheduleDate = DateUtils.addSeconds(scheduleDate, staggerSecs);
                    }
                }

                deploymentEntity = new DeploymentEntity();
                deploymentEntity.setName(deployment.getDeploymentName());
                deploymentEntity.setDeploymentDesc(deployment.getDeploymentDescription());
                deploymentEntity.setId(UUID.randomUUID().toString());
                deploymentEntity.setAllUsersAllowed(deployment.isAllUsersAllowed());
                deploymentEntity.setCompliant(false);
                deploymentEntity.setBrownfield(deployment.isBrownfield());

                logger.debug("create the deployment in DB " + deploymentEntity.getId());

                // update deployments table with storage devices in the deployment parameter.
                // also set the component ASMGUID
                List<SelectedServer> processedServers = null;

                try {
                    processedServers = updateFromComponentValues(serviceTemplate, deploymentEntity, selectedServers,
                            null);
                } catch (AsmManagerNoServerException nse) {
                    throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST, AsmManagerMessages
                            .serversNotAvailableForDeployment(filterResponse.getFailedPoolName()));
                }

                // fill raid config from filter response. Use server list created by step above
                if (raidIsRequired(serviceTemplate)) {
                    setRAIDConfiguration(serviceTemplate.getComponents(), processedServers);
                }

                // Create empty deployment so that we get a deployment id to assign IPs to
                DeploymentEntity deploymentEntityCreated = deploymentDAO.createDeployment(deploymentEntity);
                deploymentId = deploymentEntityCreated.getId();
                deployment.setId(deploymentId);

                if (!deployment.isBrownfield()) { // There is no Network so this will fail for Brownfield
                    processComponentNetworksAndHostnames(deployment, null);
                    processVmNames(deployment.getServiceTemplate(), deployment);
                    processStorageVolumes(deployment);
                    String tempXml = MarshalUtil.marshal(serviceTemplate);
                    ServiceTemplate templateToValidate = MarshalUtil.unmarshal(ServiceTemplate.class, tempXml);
                    serviceTemplateUtil.decryptPasswords(templateToValidate);
                    serviceTemplateValidator.validateTemplate(templateToValidate,
                            new ServiceTemplateValidator.ValidationOptions(true, true, true));
                    if (!templateToValidate.getTemplateValid().isValid()) {
                        throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                                serviceTemplateValidator
                                        .getAllServiceTemplateValidationMessages(templateToValidate));
                    }
                }

                // add title if needed
                ensureResourceHasTitle(serviceTemplate);
                ServiceTemplateUtil.ensureRelatedComponents(serviceTemplate);

                //If we're managing the firmware and have a firmware selected, set it.
                boolean manageFirmware = firmwareUtil.manageDeploymentFirmware(deployment, deploymentEntity);

                // now add references
                deploymentEntity.setAssignedUserList(new HashSet<DeploymentUserRefEntity>());
                if (deployment.getAssignedUsers() != null) {
                    for (User user : deployment.getAssignedUsers()) {
                        DeploymentUserRefEntity de = new DeploymentUserRefEntity();
                        de.setUserId(user.getUserSeqId());
                        de.setDeploymentId(deploymentId);
                        de.setId(UUID.randomUUID().toString());
                        deploymentEntity.getAssignedUserList().add(de);
                    }
                }

                List<AddOnModuleComponentEntity> addOnModuleComponentEntities = addOnModuleComponentsDAO
                        .getAll(true);
                updateAddOnMoulesOnDeployment(addOnModuleComponentEntities, serviceTemplate, deploymentEntity);

                // Parse the ServiceTemplate for Host Names and VM Names
                Map<String, Set<String>> usedDeploymentNames = parseUsedDeploymentNames(
                        deployment.getServiceTemplate());
                updateDeploymentNameRefsOnDeployment(deploymentEntity, usedDeploymentNames);

                deploymentEntity.setMarshalledTemplateData(MarshalUtil.marshal(serviceTemplate));

                String jsonData = toJson(deployment);

                IJobManager jm = getJobManager();

                /**
                 *  This is a new feature.  Firmware jobs are run as children of the Deployment job.
                 */
                job = jm.createNamedJob(ServiceDeploymentJob.class);
                job.getJobDataMap().put(ServiceDeploymentJob.ServiceDeploymentJob_SERVICE_KEY_DATA, jsonData);

                // Create a trigger and associate it with the schedule, job,
                // and some arbitrary information. The boolean means "start now".
                Trigger trigger;
                if (scheduleDate == null) {
                    logger.info("Scheduling deployment " + deployment.getDeploymentName() + " to begin at "
                            + scheduleDate);
                    trigger = jm.createNamedTrigger(schedBuilder, job, true);
                } else {
                    SimpleTriggerImpl t = new SimpleTriggerImpl();
                    t.setRepeatCount(0);
                    t.setName(UUID.randomUUID().toString());
                    t.setGroup(FirmwareUpdateJob.class.getSimpleName()); // Matches the above trigger creation
                    t.setStartTime(scheduleDate);
                    trigger = t;
                }

                jm.scheduleJob(job, trigger);
                logger.info("checking and starting the scheduler");
                if (!jm.getScheduler().isStarted()) {
                    jm.getScheduler().start();
                    logger.info("scheduler started");
                }
                // Return the job name.
                jobName = job.getJobDataMap().getString(JobManager.JM_JOB_HISTORY_JOBNAME);
                // discoveryRequest.setId(jobName);
                // discoveryRequest.setStatus(DiscoveryStatus.INPROGRESS);

                logger.debug("update the deployment in DB if job was successfully created.");
                deploymentEntity.setJobId(jobName);

                logService.logMsg(
                        AsmManagerMessages.deployedServiceTemplate(serviceTemplate.getTemplateName(),
                                deploymentEntity.getName()).getDisplayMessage(),
                        LogMessage.LogSeverity.INFO, LogMessage.LogCategory.DEPLOYMENT);

                deploymentDAO.updateDeployment(deploymentEntity);

                // deployment created. Update appliance status for Getting Started calls.
                WizardStatus ws = ProxyUtil.getAlcmStatusProxy().getWizardStatus();
                if (!ws.getIsDeploymentCompleted()) {
                    ws.setIsDeploymentCompleted(true);
                    ProxyUtil.getAlcmStatusProxy().updateWizardStatus(ws);
                }
            }

            if (servletResponse != null) {
                servletResponse.setStatus(Response.Status.ACCEPTED.getStatusCode());
                Link jobStatusLink = ProxyUtil.buildJobLink("Deployment", jobName, servletRequest, uriInfo,
                        httpHeaders);
                servletResponse.setHeader("Link", RestUtil.toLinkHeaderString(jobStatusLink));
            }

            return firstDeployment;
        } catch (Exception e) {
            logger.error("Exception while creating deployment", e);
            if (StringUtils.isNotEmpty(deploymentId)) {
                deleteDeployment(deploymentId);
            } else if (deploymentEntity != null && deploymentEntity.getDeployedDevices() != null) {
                // Deployment has not yet been saved to db, but we need to return servers to Available
                for (DeviceInventoryEntity server : deploymentEntity.getDeployedDevices()) {
                    if (DeviceType.isServer(server.getDeviceType())) {
                        deviceInventoryDAO.setDeviceState(server, DeviceState.READY, true);
                    }
                }
            }
            if (e instanceof LocalizedWebApplicationException) {
                throw (LocalizedWebApplicationException) e;
            } else {
                throw new LocalizedWebApplicationException(Response.Status.INTERNAL_SERVER_ERROR,
                        AsmManagerMessages.internalError());
            }
        }
    }

    public static void updateAddOnMoulesOnDeployment(List<AddOnModuleComponentEntity> addOnModuleComponentEntities,
            ServiceTemplate serviceTemplate, DeploymentEntity deployment) {
        //remove all addOnModules to clean up the list.
        Map<String, AddOnModuleEntity> currentModuleMap = new HashMap<>();
        for (AddOnModuleEntity addOnModuleEntity : deployment.getAddOnModules()) {
            currentModuleMap.put(addOnModuleEntity.getName(), addOnModuleEntity);
        }
        Set<AddOnModuleEntity> updatedEntites = new HashSet<>();
        for (ServiceTemplateComponent component : serviceTemplate.getComponents()) {
            if (component.getType().equals(ServiceTemplateComponentType.SERVICE)) {
                for (AddOnModuleComponentEntity aOMComponent : addOnModuleComponentEntities) {
                    if (component.getName().equals(aOMComponent.getName())) {
                        AddOnModuleEntity currentEntity = currentModuleMap
                                .get(aOMComponent.getAddOnModuleEntity().getName());
                        if (currentEntity == null) {
                            currentEntity = aOMComponent.getAddOnModuleEntity();
                        }
                        updatedEntites.add(currentEntity);
                        break;
                    }
                }
            }
        }
        deployment.getAddOnModules().clear();
        deployment.getAddOnModules().addAll(updatedEntites);
    }

    /**
     * return true if any of components require raid configuration
     * @param serviceTemplate
     * @return
     */
    private boolean raidIsRequired(ServiceTemplate serviceTemplate) {
        for (ServiceTemplateComponent component : serviceTemplate.getComponents()) {
            if (component.getType() == ServiceTemplateComponentType.SERVER) {
                for (ServiceTemplateCategory resource : component.getResources()) {
                    ServiceTemplateSetting raidConfig = resource
                            .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_RAID_ID);
                    if (raidConfig != null && StringUtils.isNotEmpty(raidConfig.getValue())) {
                        String depTarget = raidConfig.getDependencyTarget();
                        String depValue = raidConfig.getDependencyValue();
                        if (StringUtils.isNotEmpty(depTarget) && StringUtils.isNotEmpty(depValue)) {
                            ServiceTemplateSetting target = resource.getParameter(depTarget);
                            if (target != null && Arrays.asList(depValue.split(",")).contains(target.getValue())) {
                                return true;
                            }
                        }
                    }
                }
            }
        }
        return false;
    }

    /**
     * For each server template component with RAID required Find corresponding server from filter response and it's RAID config.
     * @param components
     * @param selectedServers   Warning - this list will be modified!
     */
    private void setRAIDConfiguration(List<ServiceTemplateComponent> components,
            List<SelectedServer> selectedServers) {
        for (ServiceTemplateComponent component : components) {
            if (component.getType() == ServiceTemplateComponentType.SERVER) {
                for (ServiceTemplateCategory resource : component.getResources()) {
                    ServiceTemplateSetting raidConfig = resource
                            .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_RAID_ID);
                    if (raidConfig != null && StringUtils.isNotEmpty(raidConfig.getValue())) {
                        Iterator<SelectedServer> iterator = selectedServers.iterator();
                        while (iterator.hasNext()) {
                            SelectedServer ss = iterator.next();
                            if (component.getId().equals(ss.getComponentId())) {
                                raidConfig.setRaidConfiguration(ss.getRaidConfiguration());
                                iterator.remove();
                                break;
                            }
                        }
                        if (raidConfig.getRaidConfiguration() == null) {
                            logger.error("RAID Configuration was not set for deployment template component ID="
                                    + component.getId() + ", IP=" + component.getIP());
                            throw new LocalizedWebApplicationException(Response.Status.INTERNAL_SERVER_ERROR,
                                    AsmManagerMessages.internalError());
                        }
                    }
                }
            }
        }
    }

    private DeploymentEnvironment initCachedEnvironment() {
        DeploymentEnvironment deploymentEnvironment = new DeploymentEnvironment();
        deploymentEnvironment
                .setDeployments(deploymentDAO.getAllDeployment(DeploymentDAO.DEVICE_INVENTORY_ENTITIES));

        // service context, needed to find out if current user has access to the pool
        deploymentEnvironment.setUserID(asmManagerUtil.getCurrentUser(this.servletRequest).getUserSeqId());

        return deploymentEnvironment;
    }

    /**
     * Auto generate host names if needed
     * Allowed values are ${num} (an auto-generated unique number), ${service_tag}, ${model} and ${vendor}.
     *
     * @param serviceTemplate
     */
    private void processHostnames(ServiceTemplate serviceTemplate, Deployment deployment, String componentId,
            boolean isMigrate) {
        List<String> reservedHostNames = deploymentNamesRefDAO.getAllNamesByType(DeploymentNamesType.OS_HOST_NAME);
        Set<String> allHostnames = new HashSet<>();
        if (reservedHostNames != null) {
            allHostnames.addAll(reservedHostNames);
        }
        HostnameUtil hostnameUtil = new HostnameUtil();
        for (ServiceTemplateComponent component : serviceTemplate.getComponents()) {
            if (component.getType() != ServiceTemplateComponentType.SERVER
                    && component.getType() != ServiceTemplateComponentType.VIRTUALMACHINE)
                continue;

            if (componentId != null && !componentId.equals(component.getId()))
                continue;

            DeviceInventoryEntity server = null;
            if (ServiceTemplateComponentType.SERVER.equals(component.getType())) {
                server = deviceInventoryDAO.getDeviceInventory(component.getAsmGUID());
                if (server == null) {
                    logger.error("Cannot find server in the inventory by refId = " + component.getAsmGUID());
                    throw new AsmManagerRuntimeException(
                            "Cannot find server in the inventory by refId = " + component.getAsmGUID());
                }
            }

            for (ServiceTemplateCategory resource : component.getResources()) {
                for (ServiceTemplateSetting param : resource.getParameters()) {
                    if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_GENERATE_HOSTNAME_ID
                            .equals(param.getId())) {
                        if (param.getValue() != null && param.getValue().equals("true")) {
                            ServiceTemplateSetting htSet = component.getTemplateSetting(
                                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HOSTNAME_TEMPLATE_ID);
                            String hostnameTemplate = ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HOSTNAME_DEFAULT_TEMPLATE;
                            ServiceTemplateSetting hostnameSet = component.getTemplateSetting(
                                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HOSTNAME_ID);
                            if (hostnameSet == null) {
                                logger.error("Cannot find hostname setting in the service template for component = "
                                        + component.getAsmGUID());
                                throw new AsmManagerRuntimeException(
                                        "Cannot find hostname setting in the service template for component = "
                                                + component.getAsmGUID());
                            }
                            if (htSet != null && StringUtils.isNotEmpty(htSet.getValue())) {
                                hostnameTemplate = htSet.getValue();
                            }

                            if (isMigrate && HostnameUtil.mustRegenerateHostname(hostnameTemplate)) {
                                hostnameSet.setValue(null);
                            }

                            //hostnameSet will be empty string if it's never been set. The hostname will be set already for templates when the deployment was created/updated last.
                            //Want to prevent resetting the hostname.
                            if (StringUtils.isEmpty(hostnameSet.getValue())) {
                                hostnameTemplate = hostnameUtil.generateHostname(hostnameTemplate, component,
                                        server, allHostnames);

                                // only check for dups
                                if (!allHostnames.add(hostnameTemplate)) {
                                    logger.error("Duplicate generated hostname: " + hostnameSet.getValue());
                                    throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                                            AsmManagerMessages.duplicateHostname(hostnameTemplate));
                                } else {
                                    hostnameSet.setValue(hostnameTemplate);
                                    allHostnames.add(hostnameTemplate);
                                }
                            }

                            // last minute check
                            if (!HostnameUtil.isValidHostName(hostnameSet.getValue(), component)) {
                                logger.error("Invalid generated hostname: " + hostnameSet.getValue());
                                throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                                        AsmManagerMessages.invalidHostname(hostnameSet.getValue()));
                            }

                        } else {
                            if (deployment.getNumberOfDeployments() > 1) {
                                logger.error(
                                        "Auto generate hostname set to false and asked number of deployments > 1: "
                                                + deployment.getNumberOfDeployments());
                                throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                                        AsmManagerMessages.mustSetAutoGenerateHostname());

                            }
                        }
                    }
                }
            }
            validateHostname(component);
        }
    }

    /**
     * Validate the hostname set for a component, server or VM, except VM clones.
     * @param component
     */
    private void validateHostname(ServiceTemplateComponent component) {
        if (component != null
                && !ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_COMPID_HW.equals(component.getComponentID())
                && !component.hasSanISCSIBoot()) {
            ServiceTemplateSetting hostnameSetting = component
                    .getTemplateSetting(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HOSTNAME_ID);
            if (hostnameSetting != null) {
                if (StringUtils.isNotEmpty(hostnameSetting.getValue())) {
                    ServiceTemplateSetting repoSetting = component
                            .getTemplateSetting(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_IMAGE_ID);
                    if (repoSetting != null && StringUtils.isNotEmpty(repoSetting.getValue())) {
                        String repoName = repoSetting.getValue();
                        String osType = serviceTemplateUtil.findTask(repoName);
                        String hostname = hostnameSetting.getValue(); // will not be null, checked above
                        if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_WINDOWS2012_VALUE.equals(osType)
                                || ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_WINDOWS2008_VALUE
                                        .equals(osType)) {
                            if (hostname.length() > 15) {
                                throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                                        AsmManagerMessages.hostnameTooLong(hostname));
                            }
                        }
                    }
                } else {
                    logger.error("Attempt to deploy a server or VM with empty host name: component ID="
                            + component.getId() + ", GUID=" + component.getAsmGUID());
                    throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                            AsmManagerMessages.invalidHostname("<empty>"));
                }
            }
        }
    }

    /**
     * Now ensure we have a title for every resource and replace related component id with the new ids
     * @param serviceTemplate
     */
    private void ensureResourceHasTitle(ServiceTemplate serviceTemplate) {
        Map<String, Set<String>> resourceTypeTitles = new HashMap<>();
        for (ServiceTemplateComponent component : serviceTemplate.getComponents()) {
            for (ServiceTemplateCategory resource : component.getResources()) {
                boolean foundTitle = false;
                for (ServiceTemplateSetting param : resource.getParameters()) {
                    if (param.getValue() != null
                            && ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID.equals(param.getId())
                            && !param.getValue().isEmpty()) {
                        foundTitle = true;
                        break;
                    }
                }

                if (!foundTitle) {
                    String title = component.getPuppetCertName();
                    String resourceType = resource.getId();
                    if (resourceTypeTitles.get(resourceType) == null) {
                        resourceTypeTitles.put(resourceType, new HashSet<String>());
                    }
                    resourceTypeTitles.get(resourceType).add(title);
                    ServiceTemplateSetting titleParam = new ServiceTemplateSetting();
                    titleParam.setId(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID);
                    titleParam.setValue(title);
                    titleParam.setType(ServiceTemplateSetting.ServiceTemplateSettingType.STRING);
                    titleParam.setRequired(false);
                    titleParam.setHideFromTemplate(true);
                    resource.getParameters().add(titleParam);
                }
            }
        }
    }

    /**
     *
     * @param deployment
     * @param deploymentToUpdate
     */
    private void updateServiceTemplateServers(Deployment deployment, DeploymentEntity deploymentToUpdate) {
        ServiceTemplate serviceTemplate = deployment.getServiceTemplate();

        ServiceTemplate serviceTemplateOriginal = MarshalUtil.unmarshal(ServiceTemplate.class,
                deploymentToUpdate.getMarshalledTemplateData());
        List<ServiceTemplateComponent> newComponents = getNewComponents(serviceTemplateOriginal, serviceTemplate);
        ServiceTemplate newTemplate = new ServiceTemplate();
        newTemplate.setComponents(newComponents);

        if (!deployment.isBrownfield()) {
            DeploymentFilterResponse filterResponse = filterAvailableServers(newTemplate, 1, true);
            if (filterResponse.getNumberRequestedServers() > filterResponse.getNumberSelectedServers()) {
                Map<String, String> rejectServersReason = new HashMap<String, String>();
                sortRejectServerResponse(rejectServersReason, filterResponse.getRejectedServers(),
                        filterResponse.getNumberSelectedServers());
                throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                        AsmManagerMessages.serverRejectForDeployment(rejectServersReason));
            }

            try {
                // this list will mutate. We need it later unchanged.
                List<SelectedServer> processedServers = updateFromComponentValues(serviceTemplate,
                        deploymentToUpdate, filterResponse.getSelectedServers(), newComponents);
                // fill raid config from filter response
                if (raidIsRequired(newTemplate)) {
                    setRAIDConfiguration(newTemplate.getComponents(), processedServers);
                }

            } catch (AsmManagerNoServerException nse) {
                throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                        AsmManagerMessages.serversNotAvailableForDeployment(filterResponse.getFailedPoolName()));
            }
        } else { // Filtering will not find the required servers (they will show as deployed) so must create for Brownfield
            List<SelectedServer> selectedServers = new ArrayList<SelectedServer>();
            selectedServers.addAll(brownfieldUtil.getSelectedServersForBrownfield(serviceTemplate));
            List<SelectedServer> processedServers = updateFromComponentValues(serviceTemplate, deploymentToUpdate,
                    selectedServers, newComponents);
        }

        //After the update some title values of parameters will still not be correct, however they should match the puppetcertname
        for (ServiceTemplateComponent component : newComponents) {
            if (ServiceTemplateComponentType.SERVER == component.getType()
                    || ServiceTemplateComponentType.VIRTUALMACHINE == component.getType()) {
                for (ServiceTemplateCategory resource : component.getResources()) {
                    for (ServiceTemplateSetting parameter : resource.getParameters()) {
                        if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID.equals(parameter.getId())) {
                            logger.debug("Updating title for asmguid: " + component.getAsmGUID()
                                    + " Settgin parameter value to: " + component.getPuppetCertName());
                            parameter.setValue(component.getPuppetCertName());
                        }
                    }
                }
            }
        }

    }

    private void sortRejectServerResponse(Map<String, String> rejectServersReason,
            List<RejectedServer> rejectedServers, int numOfAvailableServers) {
        Collections.sort(rejectedServers, new SortByReason());
        for (RejectedServer rs : rejectedServers)
            rejectServersReason.put(rs.getIpaddress(), rs.getReason());
        //add overall count of servers failed in the end
        rejectServersReason.put("",
                rejectedServers.size()
                        + " servers could not be chosen for deployment. Number of available servers: "
                        + numOfAvailableServers);

    }

    /**
     * Identifies and returns components in the new ServiceTemplate that do not exist in the original ServiceTemplate.
     * 
     * @param originalServiceTemplate the ServiceTemplate typically from the original deployment.
     * @return newServiceTemplate the ServiceTemplate when a Service is redeployed (possibly due to scale up feature) and 
     *       which may contain new Components that were not in the original deployment.
     */
    private List<ServiceTemplateComponent> getNewComponents(ServiceTemplate originalServiceTemplate,
            ServiceTemplate newServiceTemplate) {
        List<ServiceTemplateComponent> newComponents = new ArrayList<ServiceTemplateComponent>();
        Iterator<ServiceTemplateComponent> iterator = newServiceTemplate.getComponents().iterator();
        while (iterator.hasNext()) {
            ServiceTemplateComponent stc = iterator.next();
            boolean inOrig = false;

            for (ServiceTemplateComponent stcOrig : originalServiceTemplate.getComponents()) {
                logger.trace("Comparing persisted id: " + stcOrig.getId() + " Against newer: " + stc.getId());
                if (stcOrig.getId().equals(stc.getId())) {
                    inOrig = true;
                    break;
                }
            }

            if (!inOrig)
                newComponents.add(stc);
        }

        logger.trace("ServiceTemplateOriginal component count: " + originalServiceTemplate.getComponents().size()
                + " Deployment component count: " + newServiceTemplate.getComponents().size()
                + " After removal count: " + newComponents.size());

        return newComponents;
    }

    @Override
    public Deployment updateDeployment(String deploymentId, Deployment deployment) throws WebApplicationException {
        logger.debug("update Deployment Entered for deploymentId: " + deploymentId);

        DeploymentEntity deploymentFromDb = null;
        DeploymentStatusType originalDeploymentStatus = null;
        try {
            // WARNING: The call to update the Update the Status to In_Progress MUST be first as it ensures no other 
            //          calls to update a Deployment can be made concurrently.  This call MUST be first in the this
            //          method.  Do not remove it from the start/top of the method call.
            deploymentFromDb = deploymentDAO.getDeployment(deploymentId, DeploymentDAO.ALL_ENTITIES);
            originalDeploymentStatus = deploymentFromDb.getStatus();
            deploymentFromDb = deploymentDAO.updateDeploymentStatusToInProgress(deploymentId);

            // Set the name and description
            deploymentFromDb.setName(deployment.getDeploymentName());
            deploymentFromDb.setDeploymentDesc(deployment.getDeploymentDescription());

            /*
             *  Catalog or service compliance flag changed. No other work is needed.
             */
            if (isFirmwareStatusUpdateCall(deployment, deploymentFromDb)) {
                deploymentFromDb.setStatus(originalDeploymentStatus);
                // Determine whether the firmware is being managed and which repository is used
                firmwareUtil.manageDeploymentFirmware(deployment, deploymentFromDb);

                // We must now save, or the Firmware Repository will not be available later during processing
                deploymentDAO.updateDeployment(deploymentFromDb);

                // Now process the new status
                this.serviceDeploymentUtil.updateDeploymentComplianceAfterCatalogChange(deploymentFromDb);

                deployment.setCompliant(deploymentFromDb.isCompliant());
                deployment.setDeploymentHealthStatusType(calculateDeploymentHealthStatusType(deployment));
                logger.debug("Update Deployment Finished for deploymentId: " + deploymentId);
                return deployment;
            }

            DeploymentEntity duplicateCheck = deploymentDAO.getDeploymentByName(deployment.getDeploymentName(),
                    DeploymentDAO.NONE);
            if (duplicateCheck != null && !duplicateCheck.getId().equals(deployment.getId())) {
                logger.warn("Update deployment failed, the name " + deployment.getDeploymentName()
                        + "is already in use.");
                throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                        AsmManagerMessages.renameToDuplicateName(deployment.getDeploymentName()));
            }

            ServiceTemplate serviceTemplate = deployment.getServiceTemplate();

            if (!deployment.isTeardown()) {
                DeploymentValid deploymentValid = deploymentValidator.validateDeployment(deployment, true);
                if (deploymentValid != null && !deploymentValid.isValid()) {
                    logger.error("Validation failed for create Deployment");
                    throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                            new AsmDetailedMessageList(deploymentValid.getMessages()));
                }
            }

            // If teardown specified, ensure servers are being torn down. That is currently required
            // because servers may be using pool resources, e.g. mac addresses or other virtual
            // identities
            if (deployment.isTeardown() && !deployment.isIndividualTeardown()) {
                if (serviceTemplate != null && serviceTemplate.getComponents() != null) {
                    for (ServiceTemplateComponent component : serviceTemplate.getComponents()) {
                        if (ServiceTemplateComponentType.SERVER == component.getType()) {
                            if (!component.isTeardown()) {
                                logger.warn("Teardown requested for deployment " + deploymentId
                                        + " but some servers did not have teardown set");
                                throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                                        AsmManagerMessages.deploymentTeardownMustIncludeServers());
                            }
                        }
                    }
                }
            }

            // If teardown is requested, ensure that resources marked for teardown are not used in other services
            // CLUSTER and STORAGE types are checked
            if (deployment.isTeardown()) {
                validateTeardownRequest(deploymentId, serviceTemplate);
            }

            if (deployment.isBrownfield()) {
                deployment = brownfieldUtil.getDeploymentWithOnlyDevicesInInventory(deployment);
                if (!deployment.getServiceTemplate()
                        .containsServiceTemplateComponentOfType(ServiceTemplateComponentType.SERVER)) {
                    logger.warn("Update deployment failed as there are no servers available for "
                            + deployment.getDeploymentName());
                    throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                            AsmManagerMessages.noServersAvailableForDeployment(deployment.getDeploymentName()));
                }
            }
            User currentUser = this.asmManagerUtil.getCurrentUser(this.servletRequest);

            if (!checkUserPermissions(deploymentFromDb, currentUser)) {
                logger.debug("Refused access to deployment ID=" + deploymentId + " for user "
                        + asmManagerUtil.getUserId() + " because of lack of permissions");
                throw new LocalizedWebApplicationException(Response.Status.NOT_FOUND,
                        AsmManagerMessages.deploymentNotFound(deploymentId));
            }

            for (DeviceInventoryEntity dev : deploymentFromDb.getDeployedDevices()) {
                dev = deviceInventoryDAO.getDeviceInventory(dev.getRefId());
                if (DeviceType.isServer(dev.getDeviceType())) {
                    deviceInventoryDAO.setDeviceState(dev, DeviceState.READY, true);
                }
            }
            deploymentFromDb.getDeployedDevices().clear();
            for (DeploymentDevice currInvDevice : deployment.getDeploymentDevice()) {
                DeviceInventoryEntity theDevice = deviceInventoryDAO.getDeviceInventory(currInvDevice.getRefId());

                if (theDevice != null) {
                    deploymentFromDb.getDeployedDevices().add(theDevice);
                    if (DeviceType.isServer(theDevice.getDeviceType())) {
                        deviceInventoryDAO.setDeviceState(theDevice,
                                DeviceState.fromDeploymentStatusType(deployment.getStatus()), true);
                    }
                }
            }

            //We can't choose new servers from the ui when updating services that include servers.  We need to do it now.
            updateServiceTemplateServers(deployment, deploymentFromDb);

            // this must be followed by updateServiceTemplateServers - as title will be empty at this time, no servers selected yet.
            ensureResourceHasTitle(serviceTemplate);
            ServiceTemplateUtil.ensureRelatedComponents(serviceTemplate);

            //Now encrypt new passwords and keep the ones already present
            ServiceTemplate origTemplate = MarshalUtil.unmarshal(ServiceTemplate.class,
                    deploymentFromDb.getMarshalledTemplateData());

            // HACK: strip confirm password fields from original template. Password / confirm
            // password validation really only needs to happen for new passwords passed in, not
            // on saved data. In general these shouldn't be present in the saved template data
            // because they are stripped out as part of updateFromComponentValues, but
            // previous code didn't strip out e.g. the domain confirm password so we might have
            // pre-existing services that still have those fields.
            serviceTemplateUtil.stripConfirmPasswordParameters(origTemplate);
            serviceTemplateUtil.encryptPasswords(serviceTemplate, origTemplate);
            serviceTemplateUtil.setHiddenValues(serviceTemplate);

            if (!deployment.isTeardown() && !deployment.isBrownfield()) {
                processComponentNetworksAndHostnames(deployment, origTemplate);
                processVmNames(deployment.getServiceTemplate(), deployment);
                processStorageVolumes(deployment);
            }

            // now that we have updated the service template we need to rerun validation
            if (!deployment.isBrownfield()) {
                // we have to ignore existing components and validate only new
                List<String> existingComponents = new ArrayList<>();
                List<ServiceTemplateComponent> newComponents = getNewComponents(origTemplate, serviceTemplate);
                for (ServiceTemplateComponent componentToCheck : serviceTemplate.getComponents()) {
                    if (!newComponents.contains(componentToCheck)) {
                        existingComponents.add(componentToCheck.getId());
                    }
                }

                serviceTemplateValidator.validateTemplate(serviceTemplate,
                        new ServiceTemplateValidator.ValidationOptions(true, !deployment.isConfigurationChange()
                                && (deployment.isScaleUp() || (!deployment.isRetry() && !deployment.isTeardown())),
                                true),
                        existingComponents);
            }

            boolean templateValid = serviceTemplate.getTemplateValid().isValid();
            if (!templateValid) {
                if (!deployment.isTeardown() || deployment.isIndividualTeardown()) {
                    // service template is invalid dont save and throw error
                    logger.error("Validation failed for deployment service template");
                    throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                            serviceTemplateValidator.getAllServiceTemplateValidationMessages(serviceTemplate));
                }
            }

            // reset list of attempted servers
            if (deployment.isRetry()) {
                for (ServiceTemplateComponent component : serviceTemplate.getComponents()) {
                    if (ServiceTemplateComponentType.SERVER.equals(component.getType())) {
                        ServiceTemplateSetting setting = component.getTemplateSetting(
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_ATTEMPTED_SERVERS);
                        if (setting != null)
                            setting.setValue(null);
                    }
                }

                // Update the Components Network Templates with values from the Database for Networks
                ProxyUtil.setProxyHeaders(networkService, servletRequest);

                networkingUtil.updateExistingNetworkTemplates(deployment.getServiceTemplate().getComponents(),
                        networkService);
            }

            // validation passed so update
            if (templateValid) {
                deploymentFromDb.setTemplateValid(Boolean.TRUE);
            }
            deploymentFromDb.setMarshalledTemplateData(MarshalUtil.marshal(serviceTemplate));

            if (deploymentFromDb.getVmList() != null) {
                deploymentFromDb.getVmList().clear();
                if (deployment.getVms() != null)
                    for (VM currVm : deployment.getVms()) {
                        VMRefEntity newRefEntity = new VMRefEntity();
                        newRefEntity.setVmId(currVm.getCertificateName());
                        newRefEntity.setDeploymentId(deploymentFromDb.getId());
                        newRefEntity.setVmIpaddress(currVm.getVmIpaddress());
                        newRefEntity.setVmManufacturer(currVm.getVmIpaddress());
                        newRefEntity.setVmModel(currVm.getVmModel());
                        deploymentFromDb.getVmList().add(newRefEntity);
                    }
            }

            deploymentFromDb.setAllUsersAllowed(deployment.isAllUsersAllowed());
            if (deploymentFromDb.getAssignedUserList() != null) {
                deploymentFromDb.getAssignedUserList().clear();
            } else {
                deploymentFromDb.setAssignedUserList(new HashSet<DeploymentUserRefEntity>());
            }

            if (deployment.getAssignedUsers() != null) {
                for (User user : deployment.getAssignedUsers()) {
                    DeploymentUserRefEntity de = new DeploymentUserRefEntity();
                    de.setUserId(user.getUserSeqId());
                    de.setDeploymentId(deploymentFromDb.getId());
                    de.setId(UUID.randomUUID().toString());
                    deploymentFromDb.getAssignedUserList().add(de);
                }
            }

            List<AddOnModuleComponentEntity> addOnModuleComponentEntities = addOnModuleComponentsDAO.getAll(true);
            updateAddOnMoulesOnDeployment(addOnModuleComponentEntities, serviceTemplate, deploymentFromDb);

            if (!deployment.isTeardown()) {
                // Parse the new ServiceTemplate Once for Validating Deployment for Host Names, VM Names, and Volume Names
                Map<String, Set<String>> usedDeploymentNames = parseUsedDeploymentNames(
                        deployment.getServiceTemplate());
                updateDeploymentNameRefsOnDeployment(deploymentFromDb, usedDeploymentNames);
            }

            if (deployment.isRetry() || deployment.isTeardown()) {

                JobDetail job;
                String jobName;
                IJobManager jm = getJobManager();
                SimpleScheduleBuilder schedBuilder = SimpleScheduleBuilder.simpleSchedule();

                job = jm.createNamedJob(ServiceDeploymentJob.class);
                if (deployment.isScaleUp()) {
                    job.getJobDataMap().put(ServiceDeploymentJob.ServiceDeploymentJob_IS_SCALE_UP, true);
                }

                String jsonData = toJson(deployment);

                job.getJobDataMap().put(ServiceDeploymentJob.ServiceDeploymentJob_SERVICE_KEY_DATA, jsonData);
                job.getJobDataMap().put(ServiceDeploymentJob.ServiceDeploymentJob_INDIVIDUAL_TEARDOWN,
                        deployment.isIndividualTeardown());

                // Create a trigger and associate it with the schedule, job,
                // and some arbitrary information. The boolean means "start now".
                Trigger trigger = jm.createNamedTrigger(schedBuilder, job, true);
                jm.scheduleJob(job, trigger);
                logger.info("checking and starting the scheduler");
                if (!jm.getScheduler().isStarted()) {
                    jm.getScheduler().start();
                    logger.info("scheduler started");
                }

                // Return the job name.
                jobName = job.getJobDataMap().getString(JobManager.JM_JOB_HISTORY_JOBNAME);

                logger.debug("update the deployment in DB if job was successfully created.");

                if (!deployment.isTeardown()) {
                    // confusing message for actual delete operation
                    EEMILocalizableMessage msg = AsmManagerMessages.deployedServiceTemplate(
                            serviceTemplate.getTemplateName(), deployment.getDeploymentName());
                    logService.logMsg(msg.getDisplayMessage(), LogMessage.LogSeverity.INFO,
                            LogMessage.LogCategory.DEPLOYMENT);
                }

                if (servletResponse != null) {
                    servletResponse.setStatus(Response.Status.ACCEPTED.getStatusCode());
                    Link jobStatusLink = ProxyUtil.buildJobLink("Deployment", jobName, servletRequest, uriInfo,
                            httpHeaders);
                    servletResponse.setHeader("Link", RestUtil.toLinkHeaderString(jobStatusLink));
                }

            } else {
                deploymentFromDb.setStatus(originalDeploymentStatus);
            }

            deploymentDAO.updateDeployment(deploymentFromDb);

            deployment.setDeploymentHealthStatusType(calculateDeploymentHealthStatusType(deployment));

            logger.debug("Update Deployment Finished for deploymentId: " + deploymentId);
            return deployment;
        } catch (LocalizedWebApplicationException e) {
            logger.error("LocalizedWebApplicationException while updating Deployment " + deploymentId, e);
            try {
                deploymentFromDb = deploymentDAO.getDeployment(deployment.getId(),
                        DeploymentDAO.DEVICE_INVENTORY_ENTITIES);
                // return new servers to Available state
                boolean modified = restoreServersStateOnError(deployment, deploymentFromDb);
                if (deploymentFromDb != null && originalDeploymentStatus != null
                        && DeploymentStatusType.IN_PROGRESS != originalDeploymentStatus) {
                    deploymentFromDb.setStatus(originalDeploymentStatus);
                    modified = true;
                }
                if (modified) {
                    deploymentDAO.updateDeployment(deploymentFromDb);
                }
            } catch (Exception statusException) {
                logger.warn(
                        "Error restoring deploymentFromDb of " + deploymentFromDb.getName()
                                + " back to originalDeploymentState of " + originalDeploymentStatus.getValue(),
                        statusException);
            }

            throw e;
        } catch (Exception e) {
            logger.error("Exception while updating Deployment " + deploymentId, e);
            try {
                deploymentFromDb = deploymentDAO.getDeployment(deployment.getId(),
                        DeploymentDAO.DEVICE_INVENTORY_ENTITIES);
                // return new servers to Available state
                boolean modified = restoreServersStateOnError(deployment, deploymentFromDb);
                if (deploymentFromDb != null && originalDeploymentStatus != null
                        && DeploymentStatusType.IN_PROGRESS != originalDeploymentStatus) {
                    deploymentFromDb.setStatus(originalDeploymentStatus);
                    modified = true;
                }
                if (modified) {
                    deploymentDAO.updateDeployment(deploymentFromDb);
                }
            } catch (Exception statusException) {
                logger.warn(
                        "Error restoring deploymentFromDb of " + deploymentFromDb.getName()
                                + " back to originalDeploymentState of " + originalDeploymentStatus.getValue(),
                        statusException);
            }

            throw new LocalizedWebApplicationException(Response.Status.INTERNAL_SERVER_ERROR,
                    AsmManagerMessages.internalError());
        }
    }

    /**
     * Checks the deployment against the current deploymentEntity.
     *   Verifies:
     *   Change of manage firmware flags
     *   Change of Use Default Catalog flags
     *   Change of firmware repository being managed
     *
     * @param deployment
     * @param deploymentEntity
     * @return
     */
    private boolean isFirmwareStatusUpdateCall(Deployment deployment, DeploymentEntity deploymentEntity) {
        if (deployment != null && deploymentEntity != null) {
            if (deployment.isUpdateServerFirmware() != deploymentEntity.isManageFirmware()) {
                return true;
            }
            if (deployment.isUseDefaultCatalog() != deploymentEntity.isUseDefaultCatalog()) {
                return true;
            }
            final String currentFirmwareId = deploymentEntity.getFirmwareRepositoryEntity() != null
                    ? deploymentEntity.getFirmwareRepositoryEntity().getId()
                    : null;
            if (deployment.getFirmwareRepositoryId() != null) {
                if (!deployment.getFirmwareRepositoryId().equals(currentFirmwareId)) {
                    return true;
                }
            } else if (deployment.getFirmwareRepository() != null) {
                if (!deployment.getFirmwareRepository().getId().equals(currentFirmwareId)) {
                    return true;
                }
            } else if (currentFirmwareId != null) {
                return true;
            }
        } else {
            // if either deployment or deployment entity null then return true because something is wrong.
            return true;
        }
        return false;
    }

    private void validateTeardownRequest(String deploymentId, ServiceTemplate serviceTemplate) {
        logger.info("Validating teardown request - checking for shared resources");
        if (serviceTemplate != null && serviceTemplate.getComponents() != null) {
            for (ServiceTemplateComponent component : serviceTemplate.getComponents()) {
                if (component.isTeardown()) {
                    if (isSharedComponent(deploymentId, component)) {
                        logger.warn("Teardown requested for deployment " + deploymentId + " but the component, "
                                + component.getId() + ", is shared");
                        throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                                AsmManagerMessages.resourceIsSharedAcrossServices(component.getName()));
                    }
                }
            }
        }
    }

    private boolean isSharedComponent(String deploymentId, ServiceTemplateComponent component) {
        ServiceTemplateComponentType componentType = component.getType();
        logger.info(componentType.toString() + " component (" + component.getId()
                + ") is being scanned across Services");
        if (componentType != ServiceTemplateComponentType.CLUSTER
                && componentType != ServiceTemplateComponentType.STORAGE) {
            return false;
        }
        String asmGuid = null;
        ServiceTemplateCategory resource = null;
        if (component.getResources() != null) {
            for (ServiceTemplateCategory compRes : component.getResources()) {
                ServiceTemplateSetting asmGuidSetting = compRes
                        .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ASM_GUID);
                if (asmGuidSetting != null) {
                    asmGuid = asmGuidSetting.getValue();
                    resource = compRes;
                    break;
                }
            }
        }
        if (resource == null) {
            logger.warn(componentType.toString() + " resource could not be found from the deployment, "
                    + deploymentId + ", for teardown validation");
            throw new LocalizedWebApplicationException(Response.Status.INTERNAL_SERVER_ERROR,
                    AsmManagerMessages.internalError());
        }
        String resName = getResourceName(asmGuid, resource, componentType);
        if (resName == null) {
            logger.warn(componentType.toString() + " resource name could not be found from the deployment, "
                    + deploymentId + ", for teardown validation");
            throw new LocalizedWebApplicationException(Response.Status.INTERNAL_SERVER_ERROR,
                    AsmManagerMessages.internalError());
        }
        logger.debug("Resource to be checked: asm_guid = " + asmGuid + "; resource name = " + resName);
        Deployment[] deployments = null;
        deployments = getDeployments(null, null, null, new Integer(9999), Boolean.TRUE);
        if (deployments != null && deployments.length > 0) {
            for (Deployment otherDeployment : deployments) {
                logger.debug("Now checking the deployment - " + otherDeployment.getId());
                if (!otherDeployment.getId().equals(deploymentId) && otherDeployment.getServiceTemplate() != null
                        && otherDeployment.getServiceTemplate().getComponents() != null) {
                    for (ServiceTemplateComponent c : otherDeployment.getServiceTemplate().getComponents()) {
                        logger.debug("Checking component, " + c.getName() + ", in "
                                + otherDeployment.getDeploymentName());
                        if (c.getType() == componentType) {
                            List<ServiceTemplateCategory> resources = c.getResources();
                            if (resources != null) {
                                for (ServiceTemplateCategory otherResource : resources) {
                                    if (otherResource.getId().equals(resource.getId())) {
                                        logger.debug("Checking resource, " + otherResource.getId()
                                                + ", in component, " + c.getId());
                                        String otherResourceName = getResourceName(asmGuid, otherResource,
                                                componentType);
                                        logger.info("Volume name found for " + c.getName() + " in Service, "
                                                + otherDeployment.getDeploymentName() + ": " + otherResourceName);
                                        if (resName.equals(otherResourceName)) {
                                            return true;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return false;
    }

    // This private method is helper method for isSharedComponent(), and it checks the resource name only for CLUSTER and STORAGE types
    private String getResourceName(String asmGuid, ServiceTemplateCategory resource,
            ServiceTemplateComponentType compType) {

        String resourceParamNewNameId = null;
        if (compType == ServiceTemplateComponentType.CLUSTER
                && ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ESX_CLUSTER_COMP_ID.equals(resource.getId())) {
            resourceParamNewNameId = ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CLUSTER_CLUSTER_ID;
        } else if (compType == ServiceTemplateComponentType.CLUSTER
                && ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SCVMM_CLUSTER_COMP_ID.equals(resource.getId())) {
            resourceParamNewNameId = ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SCVMM_CLUSTER_CLUSTER_ID;
        } else if (compType == ServiceTemplateComponentType.STORAGE) {
            resourceParamNewNameId = ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID;
        } else {
            return null;
        }

        String resourceParamExistingNameId = ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CREATE_NEW_PREFIX
                + resourceParamNewNameId;

        if (resource.getParameters() != null && resource.getParameters().size() > 0) {
            ServiceTemplateSetting asmGuidSetting = resource
                    .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_ASM_GUID);
            if (asmGuidSetting == null)
                return null; // not all resources have asm_guid parameter
            if (!asmGuidSetting.getValue().equals(asmGuid)) {
                return null;
            }

            for (ServiceTemplateSetting param : resource.getParameters()) {
                if (param.getId().equals(resourceParamNewNameId)) {
                    if (compType == ServiceTemplateComponentType.STORAGE) {
                        return ServiceTemplateClientUtil.getVolumeNameForStorageComponent(resource);
                    } else if (!ServiceTemplateSettingIDs.SERVICE_TEMPLATE_CREATE_NEW_PREFIX
                            .equals(param.getValue())) {
                        // don't return "$new"
                        return param.getValue();
                    }
                } else if (param.getId().equals(resourceParamExistingNameId)) {
                    return param.getValue();
                }
            }
        }
        return null;
    }

    private boolean restoreServersStateOnError(Deployment deployment, DeploymentEntity deploymentFromDb) {
        boolean modified = false;
        try {
            ServiceTemplate serviceTemplate = deployment.getServiceTemplate();
            ServiceTemplate serviceTemplateOriginal = MarshalUtil.unmarshal(ServiceTemplate.class,
                    deploymentFromDb.getMarshalledTemplateData());
            List<ServiceTemplateComponent> newComponents = getNewComponents(serviceTemplateOriginal,
                    serviceTemplate);
            for (ServiceTemplateComponent component : newComponents) {
                if (ServiceTemplateComponentType.SERVER.equals(component.getType())) {
                    DeviceInventoryEntity entity = deviceInventoryDAO.getDeviceInventory(component.getAsmGUID());
                    if (entity != null) {
                        deviceInventoryDAO.setDeviceState(entity, DeviceState.READY, true);
                        deploymentFromDb.getDeployedDevices().remove(entity);
                        modified = true;
                    }
                }
            }
        } catch (Exception e) {
            logger.error("updateDeployment: Cannot restore servers to state Available", e);
            // we do not throw error here as we already in exception handler from updateDeployemnt method.
        }
        return modified;
    }

    private void processComponentNetworksAndHostnames(Deployment deployment, ServiceTemplate oldTemplate)
            throws Exception {
        Deployment deploymentDiff;
        boolean networkScaleUp = false;

        //Always perform manually assigned static ip check
        networkingUtil.validateStaticIpsIfNeeded(deployment.getServiceTemplate().getComponents());

        if (oldTemplate == null) {
            deploymentDiff = deployment;
        } else {
            Map<String, ServiceTemplateComponent> oldComponentsMap = oldTemplate.fetchComponentsMap();
            deploymentDiff = new Deployment();
            deploymentDiff.setId(deployment.getId());
            deploymentDiff.setServiceTemplate(new ServiceTemplate());
            deploymentDiff.getServiceTemplate().setId(deployment.getServiceTemplate().getId());
            Set<String> oldComponentsKeys = oldComponentsMap.keySet();
            for (ServiceTemplateComponent component : deployment.getServiceTemplate().getComponents()) {
                if (!oldComponentsKeys.contains(component.getId())) {
                    deploymentDiff.getServiceTemplate().getComponents().add(component);
                } else {
                    // scale up network case: look for empty static configuration
                    if (ServiceTemplateComponent.ServiceTemplateComponentType.SERVER.equals(component.getType())
                            || ServiceTemplateComponent.ServiceTemplateComponentType.VIRTUALMACHINE
                                    .equals(component.getType())) {
                        ServiceTemplateComponent oldComponent = oldComponentsMap.get(component.getId());
                        if (oldComponent != null) {
                            List<Network> oldNetworks = ServiceTemplateClientUtil.findStaticNetworks(oldComponent);
                            List<Network> newNetworks = ServiceTemplateClientUtil.findStaticNetworks(component);
                            if (oldNetworks.size() != newNetworks.size()) {
                                deploymentDiff.getServiceTemplate().getComponents().add(component);
                                networkScaleUp = true;
                            }
                        }
                    }
                }
            }
        }
        setProxyHeaders(networkService, servletRequest);
        List<Network> reservedNetworks = new ArrayList<>();
        try {
            if (!networkScaleUp) {
                // networking scaleup has the netwrok configuration already updated from the serviceController.addNetworkToService() method
                // therefore, we do not need to massage networks or updateStatic IPs
                networkingUtil.massageNetworks(deploymentDiff.getServiceTemplate().getComponents(), networkService);
                // reserve any manually set static ips and virtual identities - MUST DO THIS BEFORE massageVirtualIdentities
                networkingUtil.updateStaticIpsIfNeeded(deployment.getId(),
                        deploymentDiff.getServiceTemplate().getComponents(), ipAddressPoolMgr, reservedNetworks);
            }
            networkingUtil.massageVirtualIdentities(deploymentDiff, ioIdentityMgr, networkService, ipAddressPoolMgr,
                    reservedNetworks, networkScaleUp);
            networkingUtil.reserveVirtualIdentitiesForServers(deployment.getId(),
                    deploymentDiff.getServiceTemplate().getComponents(), reservedNetworks, ioIdentityMgr);
        } catch (Exception e) {
            // release all ip addresses from new components.
            logger.warn("Releasing all reserved ipaddresses during deployment setup", e);
            networkingUtil.releaseReservedComponentIPAddresses(reservedNetworks, ipAddressPoolMgr);
            throw e;
        }

        processHostnames(deployment.getServiceTemplate(), deployment, null, false);

    }

    @Override
    public Response deleteDeployment(String deploymentId) throws WebApplicationException {
        // TODO: fail if job is in progress
        logger.debug("Delete Deployment Entered for deploymentId: " + deploymentId);

        try {
            DeploymentEntity deploymentEntity = null;
            try {
                deploymentEntity = deploymentDAO.getDeployment(deploymentId,
                        DeploymentDAO.DEVICE_INVENTORY_ENTITIES);
            } catch (Exception e) {
                logger.warn("Deployment with id " + deploymentId + " does not exist.");
            }

            if (deploymentEntity != null) {
                User currentUser = this.asmManagerUtil.getCurrentUser(this.servletRequest);
                if (!checkUserPermissions(deploymentEntity, currentUser)) {
                    logger.debug("Refused access to deployment ID=" + deploymentId + " for user "
                            + asmManagerUtil.getUserId() + " because of lack of permissions");
                    throw new LocalizedWebApplicationException(Response.Status.NOT_FOUND,
                            AsmManagerMessages.deploymentNotFound(deploymentId));
                }

                try {
                    getAsmDeployerProxy().deleteDeployment(deploymentId);
                } catch (Exception e) {
                    logger.error(" Unable to delete cert names ", e);
                }

                // Release any IP/identities reserved at the service level as opposed to the
                // component level; those are released in ServiceDeploymentJob during teardown.
                //
                // This exists to release Hyper-V cluster IPs which are reserved by asm-deployer
                // during cluster creation. These calls may also be useful for customers who have
                // upgraded from an 8.0.1 or older version of ASM where the identity reservations
                // were tied solely to the service id.
                String usageGuid = deploymentEntity.getId();
                try {
                    ipAddressPoolMgr.releaseIPAddressesByUsageId(usageGuid);
                } catch (Exception e) {
                    logger.error("Unable to release IPs for deployment " + usageGuid, e);
                }
                try {
                    ioIdentityMgr.releaseIdentitiesByUsageId(usageGuid);
                } catch (Exception e) {
                    logger.error("Unable to release Identities for deployment " + usageGuid, e);
                }

                // Generally devices are removed during teardown in ServiceDeploymentJob. But
                // some cases such as a deployment that fails to create will have devices that
                // need to be cleaned up here.
                Iterator<DeviceInventoryEntity> iterator = deploymentEntity.getDeployedDevices().iterator();
                while (iterator.hasNext()) {
                    DeviceInventoryEntity device = iterator.next();
                    if (DeviceType.isServer(device.getDeviceType())) {
                        deviceInventoryDAO.setDeviceState(device, DeviceState.READY, true);
                    }
                    iterator.remove();
                }

                // remove this deployment from DB.
                deploymentDAO.deleteDeployment(deploymentId);

                logService.logMsg(
                        AsmManagerMessages.deletedDeployment(deploymentEntity.getName()).getDisplayMessage(),
                        LogMessage.LogSeverity.INFO, LogMessage.LogCategory.DEPLOYMENT);
            }
        } catch (LocalizedWebApplicationException e) {
            logger.error("LocalizedWebApplicationException while deleting service template " + deploymentId, e);
            throw e;
        } catch (Exception e) {
            logger.error("Exception while deleting service template " + deploymentId, e);
            throw new LocalizedWebApplicationException(Response.Status.INTERNAL_SERVER_ERROR,
                    AsmManagerMessages.internalError());
        }

        logger.debug("Delete Template Finished for deploymentId: " + deploymentId);
        return Response.noContent().build();

    }

    /**
     * Used to transfer pool name in exception message.
     * @param sPoolID
     * @param deviceGroups
     * @return
     */
    private String getPoolName(String sPoolID, List<DeviceGroupEntity> deviceGroups) {
        if (sPoolID == null) {
            return "No pool specified";
        } else if (sPoolID
                .compareToIgnoreCase(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_POOL_GLOBAL_ID) == 0) {
            return ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_POOL_GLOBAL_NAME;
        } else {
            if (deviceGroups != null) {
                for (int i = 0; i < deviceGroups.size(); i++) {
                    String sID = "" + deviceGroups.get(i).getSeqId();
                    if (sID.compareToIgnoreCase(sPoolID) == 0) {
                        return deviceGroups.get(i).getName();
                    }
                }
            }
        }

        logger.error("getPoolName: no pool found with ID" + sPoolID);
        return "";

    }

    /**
     * Migrate single server comnponent to another server. That will also start new Deployment Job
     * @param deploymentId
     * @param serverComponentId
     * @param serverPoolId
     * @return
     * @throws WebApplicationException
     */
    @Override
    public Deployment migrateDeployment(String deploymentId, String serverComponentId, String serverPoolId)
            throws WebApplicationException {
        return migrateDeploymentComponent(deploymentId, null, serverComponentId, serverPoolId, true);
    }

    private Deployment migrateDeploymentComponent(String deploymentId, String serverId, String componentId,
            String serverPoolId, boolean startService) throws WebApplicationException {
        if ((serverId == null && componentId == null) || deploymentId == null) {
            logger.error("Deployment parameters are missed.");
            throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                    AsmManagerMessages.internalError());
        }

        Deployment deployment = null;
        ServiceTemplate template = null;

        try {
            DeploymentEntity deploymentEntity = null;
            deploymentEntity = deploymentDAO.getDeployment(deploymentId, DeploymentDAO.ALL_ENTITIES);

            if (deploymentEntity == null) {
                logger.error("Deployment with id " + deploymentId + " does not exist.");
                throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                        AsmManagerMessages.internalError());
            }

            User currentUser = this.asmManagerUtil.getCurrentUser(this.servletRequest);
            if (!checkUserPermissions(deploymentEntity, currentUser)) {
                logger.debug("Refused access to deployment ID=" + deploymentId + " for user "
                        + asmManagerUtil.getUserId() + " because of lack of permissions");
                throw new LocalizedWebApplicationException(Response.Status.NOT_FOUND,
                        AsmManagerMessages.deploymentNotFound(deploymentId));
            }

            deployment = entityToView(deploymentEntity, currentUser);
            logger.trace("Migrate Deployment Entered for deploymentId: " + deploymentId + ", name="
                    + deployment.getDeploymentName());
            template = MarshalUtil.unmarshal(ServiceTemplate.class, deploymentEntity.getMarshalledTemplateData());
            ensureResourceHasTitle(template);
            deployment.setServiceTemplate(template);

            String serversToMigrate = "";
            String newServersList = "";

            List<String> migrationServers = new ArrayList<>();

            DeviceInventoryEntity oldServer = null;
            DeviceInventoryEntity newServer = null;
            String oldServerRefId = null;
            if (componentId != null) {
                ServiceTemplateComponent sComp = template.findComponentById(componentId);
                if (sComp != null)
                    oldServerRefId = sComp.getAsmGUID();
            } else {
                oldServerRefId = serverId;
            }
            if (deploymentEntity.getDeployedDevices() != null && deploymentEntity.getDeployedDevices().size() > 0) {
                for (DeviceInventoryEntity currDevice : deploymentEntity.getDeployedDevices()) {
                    if (currDevice.getRefId().equals(oldServerRefId)) {
                        oldServer = currDevice;
                        break;
                    }
                }
            }

            if (oldServer == null) {
                logger.error("Cannot find server : " + serverId + " in deployment " + deploymentEntity.getId());
                throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                        AsmManagerMessages.internalError());
            }
            logger.trace("Migrating FROM server  " + oldServerRefId + "/" + oldServer.getIpAddress() + "/"
                    + oldServer.getServiceTag() + " in the pool " + serverPoolId);

            if (serversToMigrate.length() > 0)
                serversToMigrate += ",";

            serversToMigrate += oldServer.getServiceTag();

            // find component in template
            ServiceTemplateComponent sComponent = null;
            String puppetCertName = PuppetModuleUtil.toCertificateName(oldServer);
            for (ServiceTemplateComponent component : template.getComponents()) {
                if (component.getType() == ServiceTemplateComponentType.SERVER) {
                    for (ServiceTemplateCategory resource : component.getResources()) {
                        if (resource.getId()
                                .equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_IDRAC_RESOURCE)
                                || resource.getId()
                                        .equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_RESOURCE)) {
                            ServiceTemplateSetting titleSet = template.getTemplateSetting(resource,
                                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID);
                            if (titleSet.getValue() != null && titleSet.getValue().equals(puppetCertName)) {
                                sComponent = component;
                                break;
                            }
                            if (sComponent != null)
                                break;
                        }
                    }
                }
            }
            if (sComponent == null) {
                logger.error("No component with server certname " + puppetCertName + " in ServiceTemplate "
                        + template.getId());
                throw new LocalizedWebApplicationException(Response.Status.INTERNAL_SERVER_ERROR,
                        AsmManagerMessages.internalError());
            }

            // will need this for error handling
            // Get all pools
            List<DeviceGroupEntity> deviceGroups = null;
            try {
                deviceGroups = getDeviceGroupDAO().getAllDeviceGroup(null, null, null);
            } catch (AsmManagerCheckedException e) {
                logger.error("Unable to get device groups", e);
                throw new LocalizedWebApplicationException(Response.Status.INTERNAL_SERVER_ERROR,
                        AsmManagerMessages.internalError());
            }

            // this will store failed server in attempted servers. We update DB later in this section.
            List<String> attemptedServers = serviceTemplateUtil.addAttemptedServers(sComponent, oldServerRefId);

            // find new server. This will throw an exception if server cannot be found.
            Map<String, DeviceInventoryEntity> newServers = new HashMap<>();
            Map<String, SelectedServer> selectedServersMap = new HashMap<>();
            if (serverPoolId == null) {
                // must use filtering logic for standard deployment
                ServiceTemplate newTemplate = new ServiceTemplate();
                newTemplate.setComponents(Arrays.asList(sComponent));

                // find max available servers
                DeploymentFilterResponse filterResponse = filterAvailableServers(newTemplate, -1, true);
                if (filterResponse.getNumberSelectedServers() > 0) {
                    for (SelectedServer ss : filterResponse.getSelectedServers()) {
                        if (attemptedServers.contains(ss.getRefId())) {
                            logger.trace("Migration: ignoring server " + ss.getRefId()
                                    + " as it is in attempted servers");
                        } else {
                            newServers.put(ss.getRefId(), deviceInventoryDAO.getDeviceInventory(ss.getRefId()));
                            selectedServersMap.put(ss.getRefId(), ss);
                        }
                    }

                    // fill raid config from filter response
                    if (raidIsRequired(newTemplate)) {
                        List<SelectedServer> selectedServers = new ArrayList<>();
                        selectedServers.addAll(filterResponse.getSelectedServers());
                        setRAIDConfiguration(newTemplate.getComponents(), selectedServers);
                    }
                }
            } else {
                // TODO: remove migrationDeviceUtils usage
                newServers = migrationDeviceUtils.migrateFilterServer(oldServer, serverPoolId, attemptedServers);
            }

            if (newServers == null || newServers.size() == 0) {
                logger.warn("No server found for this deployment with pool ID " + serverPoolId);
                throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST, AsmManagerMessages
                        .serversNotAvailableForDeployment(getPoolName(serverPoolId, deviceGroups)));
            }

            logger.trace("Migration:found " + newServers.values().size() + " servers available");
            for (DeviceInventoryEntity ns : newServers.values()) {
                if (!migrationServers.contains(ns.getRefId())) {
                    newServer = ns;
                    break;
                }
            }

            if (newServer == null) {
                if (newServers.size() > 0) {
                    logger.warn("Cannot migrate deployment " + deploymentId
                            + " - all servers in the pool have been tried out");
                }
                throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST, AsmManagerMessages
                        .serversNotAvailableForDeployment(getPoolName(serverPoolId, deviceGroups)));
            }

            // this will prevent usage of the same server in case we have multiple migration in request
            migrationServers.add(newServer.getRefId());

            if (newServersList.length() > 0)
                newServersList += ",";

            newServersList += newServer.getServiceTag();

            logger.debug("Migrating TO server  " + newServer.getRefId() + "/" + newServer.getIpAddress() + "/"
                    + newServer.getServiceTag() + " in the pool " + serverPoolId);

            if (DeviceType.isServer(oldServer.getDeviceType())) {
                deviceInventoryDAO.setDeviceState(oldServer, DeviceState.READY, true); // Q: should it rather go to ERROR?
            }

            String puppetNewCertName = PuppetModuleUtil.toCertificateName(newServer);

            // replace server cert name in all "title" settings of the component
            for (ServiceTemplateCategory resource : sComponent.getResources()) {
                for (ServiceTemplateSetting setting : resource.getParameters()) {
                    if (setting.getId().equals(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID)) {
                        if (setting.getValue() != null && setting.getValue().equals(puppetCertName)) {
                            setting.setValue(puppetNewCertName);
                        }
                    }
                }
            }

            // update component certificate
            sComponent.setPuppetCertName(puppetNewCertName);
            sComponent.setAsmGUID(newServer.getRefId());

            String origHostname = sComponent.getParameterValue(
                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_RESOURCE,
                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HOSTNAME_ID);

            // required update FQDD only - do not touch IP addresses!
            // this does not apply to servers picked by old migration code - those have identical NICs
            if (selectedServersMap.containsKey(newServer.getRefId())) {
                addNICsToNetworkConfiguration(sComponent, selectedServersMap.get(newServer.getRefId()), true);
            }
            processHostnames(template, deployment, sComponent.getId(), true);

            deploymentEntity.getDeployedDevices().remove(oldServer);
            deploymentEntity.getDeployedDevices().add(newServer);

            // serialize template. We have to save it before we add "resources" asm::baseserver
            deploymentEntity.setMarshalledTemplateData(MarshalUtil.marshal(template));

            // add asm::baseserver resource with information about original server
            ServiceTemplateCategory baseServerResource = new ServiceTemplateCategory();
            baseServerResource.setId(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_BASE_SERVER_ID);
            baseServerResource.setDisplayName("Base server for migration");

            ServiceTemplateSetting setId = new ServiceTemplateSetting();
            setId.setId("serialnumber");
            setId.setValue(oldServer.getServiceTag());
            setId.setRequired(false);
            setId.setHideFromTemplate(true);
            setId.setRequiredAtDeployment(false);
            setId.setType(ServiceTemplateSetting.ServiceTemplateSettingType.STRING);
            baseServerResource.getParameters().add(setId);

            ServiceTemplateSetting setTitle = new ServiceTemplateSetting();
            setTitle.setId(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID);
            setTitle.setValue(puppetCertName);
            setTitle.setType(ServiceTemplateSetting.ServiceTemplateSettingType.STRING);
            setTitle.setRequired(false);
            setTitle.setHideFromTemplate(true);
            setTitle.setRequiredAtDeployment(false);
            baseServerResource.getParameters().add(setTitle);

            if (!StringUtils.isEmpty(origHostname)) {
                ServiceTemplateSetting setHostname = new ServiceTemplateSetting();
                setHostname.setId(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HOSTNAME_ID);
                setHostname.setValue(origHostname);
                setHostname.setType(ServiceTemplateSetting.ServiceTemplateSettingType.STRING);
                setHostname.setRequired(false);
                setHostname.setHideFromTemplate(true);
                setHostname.setRequiredAtDeployment(false);
                baseServerResource.getParameters().add(setHostname);
            }

            sComponent.getResources().add(0, baseServerResource);

            List<AddOnModuleComponentEntity> addOnModuleComponentEntities = addOnModuleComponentsDAO.getAll(true);
            updateAddOnMoulesOnDeployment(addOnModuleComponentEntities, deployment.getServiceTemplate(),
                    deploymentEntity);

            // Parse the ServiceTemplate for Host Names and VM Names
            Map<String, Set<String>> usedDeploymentNames = parseUsedDeploymentNames(
                    deployment.getServiceTemplate());
            updateDeploymentNameRefsOnDeployment(deploymentEntity, usedDeploymentNames);

            // create a job
            String jobName = deploymentEntity.getJobId();

            if (startService) {
                JobDetail job = null;
                IJobManager jm = getJobManager();
                SimpleScheduleBuilder schedBuilder = SimpleScheduleBuilder.simpleSchedule();

                job = jm.createNamedJob(ServiceDeploymentJob.class);

                String jsonData = toJson(deployment);

                job.getJobDataMap().put(ServiceDeploymentJob.ServiceDeploymentJob_SERVICE_KEY_DATA, jsonData);
                job.getJobDataMap().put(ServiceDeploymentJob.ServiceDeploymentJob_IS_MIGRATE_DATA, true);

                // Create a trigger and associate it with the schedule, job,
                // and some arbitrary information. The boolean means "start now".
                Trigger trigger = jm.createNamedTrigger(schedBuilder, job, true);

                jm.scheduleJob(job, trigger);
                logger.info("checking and starting the scheduler");
                if (!jm.getScheduler().isStarted()) {
                    jm.getScheduler().start();
                    logger.info("scheduler started");
                }
                // Return the job name.
                jobName = job.getJobDataMap().getString(JobManager.JM_JOB_HISTORY_JOBNAME);

                logger.debug("update the deployment in DB if job was successfully created.");
                deploymentEntity.setJobId(jobName);
            } else {
                // strip settings not used by asm-deployer. This is normally called by ServiceDeploymentJob
                // note - we don't want to save it in ASM DB
                ServiceDeploymentUtil.prepareTemplateForDeployment(deployment.getServiceTemplate());
            }

            // save updated template along with deployment
            deploymentDAO.updateDeployment(deploymentEntity);

            logService.logMsg(AsmManagerMessages
                    .migratedServer(deployment.getDeploymentName(), serversToMigrate, newServersList)
                    .getDisplayMessage(), LogMessage.LogSeverity.INFO, LogMessage.LogCategory.DEPLOYMENT);

            if (servletResponse != null) {
                servletResponse.setStatus(Response.Status.ACCEPTED.getStatusCode());
                Link jobStatusLink = ProxyUtil.buildJobLink("Deployment", jobName, servletRequest, uriInfo,
                        httpHeaders);
                servletResponse.setHeader("Link", RestUtil.toLinkHeaderString(jobStatusLink));
            }

            return deployment;

        } catch (LocalizedWebApplicationException e) {
            logger.error("LocalizedWebApplicationException while migrating server in deployment " + deploymentId,
                    e);
            throw e;
        } catch (Exception e) {
            logger.error("Exception while migrating server in deployment " + deploymentId, e);
            throw new LocalizedWebApplicationException(Response.Status.INTERNAL_SERVER_ERROR,
                    AsmManagerMessages.internalError());
        }
    }

    /**
     * Check is logged user is allowed to access this deployment.
     * @param entity
     * @return
     */
    private boolean checkUserPermissions(DeploymentEntity entity, User thisUser) {

        if (thisUser.getRole().equals(AsmConstants.USERROLE_READONLY))
            return true;

        if (thisUser.getRole().equals(AsmConstants.USERROLE_ADMINISTRATOR))
            return true;

        if (entity.isAllUsersAllowed())
            return true;

        if (entity.getCreatedBy() != null && entity.getCreatedBy().equals(thisUser.getUserName()))
            return true;

        for (DeploymentUserRefEntity ref : entity.getAssignedUserList()) {
            if (thisUser.getUserSeqId() == ref.getUserId()) {
                return true;
            }
        }

        return false;
    }

    /**
     * Filtering service. Returns list of available servers per template components, plus list of rejected servers along with
     * rejection reasons.
     * @param serviceTemplate
     * @param numOfDeployments
     * @return
     * @throws WebApplicationException
     */
    @Override
    public DeploymentFilterResponse filterAvailableServers(ServiceTemplate serviceTemplate, int numOfDeployments,
            boolean requireUnique) throws WebApplicationException {

        if (serviceTemplate == null || serviceTemplate.getComponents() == null) {
            logger.error(
                    "getAvailableServers called with empty component list or non-positive number of deployments");
            throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                    AsmManagerMessages.badParametersForFiltering());
        } else if (serviceTemplate.getComponents().size() < 1) {
            // Exit early to avoid the overhead of the following calls
            return new DeploymentFilterResponse();
        }

        DeploymentEnvironment deploymentEnvironment = initCachedEnvironment();
        deploymentEnvironment.setRequireUnique(requireUnique);

        DeploymentFilterResponse response = new DeploymentFilterResponse();
        response.setSelectedServers(new ArrayList<SelectedServer>());
        response.setRejectedServers(new ArrayList<RejectedServer>());

        // the call to getAvailableServers is very expensive. If we have a service with large number of server components
        // and asking for global pool, or pool with many servers, the UI will time out on template preparation
        // therefore we need some caching for same type of server components
        Map<String, DeploymentFilterResponse> cachedResponse = new HashMap<>();

        String[] serverSources = { ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_SOURCE_MANUAL,
                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_SOURCE_POOL };
        int requestedServers = 0;
        serviceTemplateUtil.setHiddenValues(serviceTemplate);
        for (String serverSource : serverSources) {
            List<ServiceTemplateComponent> servers = ServiceTemplateUtil
                    .getServersFromSource(serviceTemplate.getComponents(), serverSource);
            requestedServers += servers.size();
            for (ServiceTemplateComponent server : servers) {
                filterAvailableServersHelper(numOfDeployments, requireUnique, deploymentEnvironment, response,
                        cachedResponse, server, serverSource);
            }
        }

        response.setNumberRequestedServers(requestedServers * numOfDeployments);
        logger.debug("Filtering service: asked " + requestedServers + " in " + numOfDeployments
                + " deployments, found: " + response.getNumberSelectedServers());

        boolean needLogging = requireUnique;

        Collections.sort(response.getRejectedServers(), new SortByReason());
        String reason = null;
        StringBuilder serversPerReason = new StringBuilder();
        for (RejectedServer rs : response.getRejectedServers()) {
            if (needLogging && !rs.getReason().equals(reason)) {
                if (reason != null) {
                    logService.logMsg(
                            AsmManagerMessages.rejectedServers(serversPerReason.toString(), reason)
                                    .getDisplayMessage(),
                            LogMessage.LogSeverity.INFO, LogMessage.LogCategory.DEPLOYMENT);
                }
                reason = rs.getReason();
                serversPerReason.setLength(0);
            }
            DeviceInventoryEntity entity = this.deviceInventoryDAO.getDeviceInventory(rs.getRefId());
            String serverStr = (entity != null) ? entity.getIpAddress() + "/" + entity.getServiceTag()
                    : rs.getRefId();
            logger.debug("Rejected server: " + serverStr + " for " + rs.getReason());
            if (serversPerReason.length() > 0)
                serversPerReason.append(',');
            serversPerReason.append(serverStr);
        }
        if (needLogging && reason != null) {
            logService.logMsg(
                    AsmManagerMessages.rejectedServers(serversPerReason.toString(), reason).getDisplayMessage(),
                    LogMessage.LogSeverity.INFO, LogMessage.LogCategory.DEPLOYMENT);
        }

        return response;
    }

    private void filterAvailableServersHelper(int numOfDeployments, boolean requireUnique,
            DeploymentEnvironment deploymentEnvironment, DeploymentFilterResponse response,
            Map<String, DeploymentFilterResponse> cachedResponse, ServiceTemplateComponent component,
            String serverSource) {
        FilterEnvironment filterEnvironment = getFilteringUtil().initFilterEnvironment(component, servletRequest);

        Pair<ServiceTemplateCategory, String> source = ServiceTemplateUtil.getServerSourceValue(component,
                serverSource);
        if (source == null) {
            logger.warn("Cannot filter server without a source: " + component);
            return;
        }

        List<ServiceTemplateSetting> sourceParameters = source.getLeft().getParameters();
        String sourceValue = source.getRight();

        String hashKey = sourceValue + filterEnvironment.hash();
        DeploymentFilterResponse responseLocal = null;
        // we can reuse the same servers. It is the case where we get full server list for manual selection
        if (!requireUnique) {
            responseLocal = cachedResponse.get(hashKey);
        }
        if (responseLocal == null) {
            responseLocal = new DeploymentFilterResponse();
            responseLocal.setSelectedServers(new ArrayList<SelectedServer>());
            responseLocal.setRejectedServers(new ArrayList<RejectedServer>());
            switch (serverSource) {
            case ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_SOURCE_POOL:
                getFilteringUtil().getAvailableServerFromPool(sourceValue, deploymentEnvironment, responseLocal,
                        filterEnvironment, numOfDeployments);
                break;
            case ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_SOURCE_MANUAL:
                getFilteringUtil().getAvailableServers(sourceValue, deploymentEnvironment, responseLocal,
                        filterEnvironment, 1);
                break;
            default:
                logger.warn("Unknown server source " + serverSource + " for " + component);
                break;
            }
            if (!requireUnique) {
                cachedResponse.put(hashKey, responseLocal);
            }
        } else {
            // we got these servers from cache: clone them
            List<SelectedServer> ssList = new ArrayList<>();
            ObjectMapper mapper = new ObjectMapper();
            for (SelectedServer s : responseLocal.getSelectedServers()) {
                try {
                    String serverString = mapper.writeValueAsString(s);
                    SelectedServer newSS = mapper.readValue(serverString, SelectedServer.class);
                    ssList.add(newSS);
                } catch (IOException e) {
                    logger.error("Exception while converting filtering response", e);
                    throw new LocalizedWebApplicationException(Response.Status.INTERNAL_SERVER_ERROR,
                            AsmManagerMessages.internalError());
                }
            }
            responseLocal.setSelectedServers(ssList);
        }

        for (SelectedServer s : responseLocal.getSelectedServers()) {
            s.setComponentId(component.getId());
        }

        // if errors, capture server pool ID/name for user message
        if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_SOURCE_POOL.equals(serverSource)) {
            if ((responseLocal.getRejectedServers().size() > 0
                    || responseLocal.getSelectedServers().size() < numOfDeployments)
                    && responseLocal.getFailedPoolId() == null) {
                responseLocal.setFailedPoolId(sourceValue);
                responseLocal.setFailedPoolName(getDeviceGroupDAO().getPoolName(sourceValue));
            }
        }

        // copy response servers
        response.getSelectedServers().addAll(responseLocal.getSelectedServers());
        for (RejectedServer rejectedServer : responseLocal.getRejectedServers()) {
            if (!response.getRejectedServers().contains(rejectedServer)) {
                response.getRejectedServers().add(rejectedServer);
            }
        }

        if (responseLocal.getFailedPoolId() != null) {
            response.setFailedPoolId(responseLocal.getFailedPoolId());
            response.setFailedPoolName(responseLocal.getFailedPoolName());
        }
    }

    private class SortByReason implements java.util.Comparator<RejectedServer> {
        @Override
        public int compare(RejectedServer x, RejectedServer y) {
            return x.getReason().toString().compareTo(y.getReason().toString());
        }
    }

    /**
     * // Services with only 1x Server (and no other storage / nics / etc)
     *      o Service reflects that Servers Health Status  
     * 
     * // Services with only 1x Server and 2x or more Arrays
     *      o Yellow Status if any Server is out of Compliance
     *      o Red Status if any component is Red  
     * 
     * // Services with More than 1 Server 
     *      o Yellow Status 
     *         - if 2x Servers are Green and Any Server goes Yellow or Red
     *     o Red Status 
     *         - if 1x Server is Green and rest are Yellow
     *         - if 1x server is Green or Yellow, everything else are Red
     *         - if all Servers are Red 
     *     
     * // Services with More than 1 Server and More than 1 Array
     *      o Yellow Status
     *         - if 2x Servers are Green or Yellow and any array goes to Yellow or Red
     *      o Red Status 
     *         - if 1x array or 1x server is Green or Yellow, and everything else are Red, we mark the service Red
     *         - if All Arrays are Red
     * 
     * // Services with only 1x Storage Array
     *      o Service reflects that Arrays' Health Status 
     *    
     * 
     * Firmware compliance status will add to above service health status.  
     * Out of compliance will result in a Yellow status for a component. 
     */
    private DeploymentHealthStatusType calculateDeploymentHealthStatusType(Deployment deployment) {

        DeploymentHealthStatusType deploymentHealthStatusType = DeploymentHealthStatusType.GREEN;

        ArrayList<DeploymentDevice> serverDevices = new ArrayList<DeploymentDevice>();
        Set<DeploymentDevice> storageDevicesSet = new HashSet<DeploymentDevice>();
        Set<String> storageRefIDs = new HashSet<>();
        ArrayList<DeploymentDevice> otherDevices = new ArrayList<DeploymentDevice>();
        ArrayList<DeploymentDevice> allDevices = new ArrayList<DeploymentDevice>();

        for (DeploymentDevice deploymentDevice : deployment.getDeploymentDevice()) {
            if (deploymentDevice.getDeviceType() != null
                    && deploymentDevice.getDeviceType().isCalculatedForResourceHealth()) {
                if (DeviceType.isServer(deploymentDevice.getDeviceType()))
                    serverDevices.add(deploymentDevice);
                else if (DeviceType.isStorage(deploymentDevice.getDeviceType())) {
                    if (storageRefIDs.add(deploymentDevice.getRefId())) {
                        storageDevicesSet.add(deploymentDevice);
                    }
                } else
                    otherDevices.add(deploymentDevice);

                allDevices.add(deploymentDevice);
            }
        }

        // Storage Devices must be unique, so we get a set and then add them to a collection for testing
        ArrayList<DeploymentDevice> storageDevices = new ArrayList<DeploymentDevice>();
        storageDevices.addAll(storageDevicesSet);

        // Any non-Compliance will turn the Service Yellow, ignore if not managed by a firmware repository
        if (!deployment.isCompliant() && deployment.getFirmwareRepositoryId() != null) {
            deploymentHealthStatusType = DeploymentHealthStatusType.YELLOW;
        }

        // TODO: ASM-5825 fix for stale compliance value fix once Deployment is updating properly
        for (DeploymentDevice deploymentDevice : allDevices) {
            if (deploymentDevice.getDeviceType().isFirmwareComplianceManaged()
                    && CompliantState.NONCOMPLIANT.getValue().equals(deploymentDevice.getCompliantState())) {
                deploymentHealthStatusType = DeploymentHealthStatusType.YELLOW;
                break;
            }
        }

        //        Scenarios
        //        0x Server and 0x Array - CHECK 1
        //        0x Server and 1x Array - CHECK 2 
        //        0x Server and 2x Array - CHECK 2        
        //        0x Server and 2+ Array - CHECK 3 
        //
        //        1x Server and 0x Array - CHECK 2 
        //        1x Server and 1x Array - CHECK 2 
        //        1x Server and 2x Array - CHECK 2        
        //        1x Server and 2+ Array - CHECK 3
        //         
        //        2x Server and 0x Array - CHECK 2        
        //        2x Server and 1x Array - CHECK 2
        //        2x Server and 2x Array - CHECK 2
        //        2x Server and 2+ Array - CHECK 5        
        //        
        //        2+ Server and 0x Array - CHECK 4 
        //        2+ Server and 1x Array - CHECK 4 
        //        2+ Server and 2x Array - CHECK 5          
        //        2+ Server and 2+ Array - CHECK 5 

        int serversGreen = this.getDevicesWithHealthStatusCount(serverDevices, DeviceHealth.GREEN);
        int serversYellow = this.getDevicesWithHealthStatusCount(serverDevices, DeviceHealth.YELLOW);
        int serversRed = this.getDevicesWithHealthStatusCount(serverDevices, DeviceHealth.RED);
        int storagesGreen = this.getDevicesWithHealthStatusCount(storageDevices, DeviceHealth.GREEN);
        int storagesYellow = this.getDevicesWithHealthStatusCount(storageDevices, DeviceHealth.YELLOW);
        int storagesRed = this.getDevicesWithHealthStatusCount(storageDevices, DeviceHealth.RED);

        int serversUknown = this.getDevicesWithHealthStatusCount(serverDevices, DeviceHealth.UNKNOWN);
        int storagesUknown = this.getDevicesWithHealthStatusCount(storageDevices, DeviceHealth.UNKNOWN);

        // UKNOWN status will result in a Yellow status, so add them to number of Yellows for each.
        serversYellow += serversUknown;
        storagesYellow += storagesUknown;

        // CHECK 1
        if (serverDevices.size() == 0 && storageDevices.size() == 0) {
            // Do nothing, we'll just use the compliance for allDevices check above to set the DeploymentHealthStatusType
        }
        // CHECK 2
        else if (serverDevices.size() <= 1 && storageDevices.size() <= 1) {
            if (this.areAnyDevicesWithHealthStatus(allDevices, DeviceHealth.RED))
                deploymentHealthStatusType = DeploymentHealthStatusType.RED;
            else if (this.areAnyDevicesWithHealthStatus(allDevices, DeviceHealth.YELLOW)
                    || this.areAnyDevicesWithHealthStatus(allDevices, DeviceHealth.UNKNOWN)) {
                deploymentHealthStatusType = DeploymentHealthStatusType.YELLOW;
            }
            //            * // Services with only 1x Server (and no other storage / nics / etc)
            //            *      o Service reflects that Servers Health Status  
        }
        // CHECK 3
        else if (serverDevices.size() <= 1 && storageDevices.size() >= 2) {
            if (serversRed > 0 || storagesGreen < 2)
                deploymentHealthStatusType = DeploymentHealthStatusType.RED;
            else if (storagesGreen >= 2 && (storagesYellow > 0 || storagesRed > 0))
                deploymentHealthStatusType = DeploymentHealthStatusType.YELLOW;
            //            * // Services with only 1x Server and 2x or more Arrays
            //            *      o Yellow Status if any component is out of Compliance
            //            *      o Red Status if any component is Red 
        }
        // CHECK 4
        else if (serverDevices.size() >= 2 && storageDevices.size() <= 1) {
            if (serversGreen >= 2 && (serversRed > 0 || serversYellow > 0))
                deploymentHealthStatusType = DeploymentHealthStatusType.YELLOW;
            else if ((serversGreen == 1 && (serversGreen < serverDevices.size())) || serversGreen == 0)
                deploymentHealthStatusType = DeploymentHealthStatusType.RED;
            //            * // Services with More than 1 Server 
            //            *      o Yellow Status 
            //            *         - if 2x Servers are Green and Any Server goes Yellow or Red
            //            *     o Red Status 
            //            *         - if 1x Server is Green and rest are Yellow
            //            *         - if 1x server is Green or Yellow, everything else are Red
            //            *         - if all Servers are Red  
        }
        // CHECK 5
        else if (serverDevices.size() >= 2 && storageDevices.size() >= 2) {
            if (serversGreen <= 1 || storagesGreen <= 1)
                deploymentHealthStatusType = DeploymentHealthStatusType.RED;
            else if ((serversGreen >= 2 && storagesGreen >= 2)
                    && ((serversYellow > 0 || storagesYellow > 0) || (serversRed > 0 || storagesRed > 0))) {
                deploymentHealthStatusType = DeploymentHealthStatusType.YELLOW;
            }
            //            *  // Services with More than 1 Server and More than 1 Array
            //            *      o Yellow Status
            //            *         - if 2x Servers are Green or Yellow and any array goes to Yellow or Red
            //            *      o Red Status 
            //            *         - if 1x array (or Server) is Green or Yellow, and everything else are Red, we mark the service Red
            //            *         - if All Arrays are Red
        }

        if (DeploymentStatusType.ERROR.equals(deployment.getStatus()))
            deploymentHealthStatusType = DeploymentHealthStatusType.RED;

        return deploymentHealthStatusType;
    }

    private boolean areAllDevicesCompliant(List<DeploymentDevice> deploymentDevices) {
        boolean isCompliant = true;

        for (DeploymentDevice deploymentDevice : deploymentDevices) {
            if (CompliantState.NONCOMPLIANT.getValue().equals(deploymentDevice.getCompliantState())) {
                isCompliant = false;
                break;
            }
        }
        return isCompliant;
    }

    // Returns a boolean indicating if ANY device is found with the given DeviceHatlhStatus
    private boolean areAnyDevicesWithHealthStatus(List<DeploymentDevice> deploymentDevices,
            DeviceHealth deviceHealth) {
        boolean withHealthStatus = false;

        for (DeploymentDevice deploymentDevice : deploymentDevices) {
            if (deviceHealth.equals(deploymentDevice.getDeviceHealth())) {
                withHealthStatus = true;
                break;
            }
        }
        return withHealthStatus;
    }

    // Returns the number of devices with the given DeviceHealth status type
    private int getDevicesWithHealthStatusCount(List<DeploymentDevice> deploymentDevices,
            DeviceHealth deviceHealth) {
        int matchingHealthStatusCount = 0;

        for (DeploymentDevice deploymentDevice : deploymentDevices) {
            if (deviceHealth.equals(deploymentDevice.getDeviceHealth())) {
                matchingHealthStatusCount++;
            }
        }
        return matchingHealthStatusCount;
    }

    @Override
    public Response exportAllDeployments() throws WebApplicationException {
        Deployment[] deployments = getDeployments("name", ListUtils.EMPTY_LIST, 0, Integer.MAX_VALUE, false);
        StreamingCSVDeploymentOutput csvOutputStream = new StreamingCSVDeploymentOutput(deployments);

        return Response.ok(csvOutputStream, MediaType.APPLICATION_OCTET_STREAM)
                .header("content-disposition", "attachment; filename = deployments.csv").build();
    }

    /*
     * Private utility class to return an output stream which produces a
     * csv formatted response.
     *
     * NOTE: There are no permissions checks done in this class. It assumes
     *       that the deployments passed in have already been filtered based
     *       on user permissions.
     */
    private class StreamingCSVDeploymentOutput implements StreamingOutput {

        private static final String DEPLOYMENT_NAME = "Name";
        private static final String DEPLOYMENT_STATUS = "Status";
        private static final String DEPLOYMENT_BY = "Deployed By";
        private static final String DEPLOYMENT_ON = "Deployed On";
        private static final String DEPLOYMENT_ROW_TEMPLATE = "\"{0}\",\"{1}\",\"{2}\",\"{3}\"\n";

        // Deployments to export
        private Deployment[] deployments;

        public StreamingCSVDeploymentOutput(Deployment[] deployments) {
            this.deployments = deployments;
        }

        @Override
        public void write(OutputStream outputStream) throws IOException, WebApplicationException {
            final PrintWriter writer = new PrintWriter(outputStream);
            final DateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");
            formatter.setTimeZone(TimeZone.getTimeZone("UTC"));

            try {
                // add the csv row headers
                writer.write(MessageFormat.format(DEPLOYMENT_ROW_TEMPLATE, DEPLOYMENT_NAME, DEPLOYMENT_STATUS,
                        DEPLOYMENT_BY, DEPLOYMENT_ON));

                // Add detail rows
                if (!ArrayUtils.isEmpty(deployments)) {
                    for (Deployment deployment : deployments) {
                        writer.write(MessageFormat.format(DEPLOYMENT_ROW_TEMPLATE,
                                (!StringUtils.isEmpty(deployment.getDeploymentName())
                                        ? deployment.getDeploymentName()
                                        : StringUtils.EMPTY),
                                (deployment.getStatus() != null ? deployment.getStatus() : StringUtils.EMPTY),
                                (!StringUtils.isEmpty(deployment.getCreatedBy()) ? deployment.getCreatedBy()
                                        : StringUtils.EMPTY),
                                (deployment.getCreatedDate() != null
                                        ? formatter.format(
                                                new Timestamp(deployment.getCreatedDate().getTimeInMillis()))
                                        : StringUtils.EMPTY)));
                        writer.flush();
                    }
                }
            } catch (Exception e) {
                logger.debug("Exception caught writing CSV service file", e);
            } finally {
                try {
                    if (writer != null) {
                        writer.close();
                    }
                } catch (Exception exception) {
                    logger.debug("Exception caught closing print writer", exception);
                }
            }
        }
    }

    private void processVmNames(ServiceTemplate serviceTemplate, Deployment deployment) {
        List<String> reservedVMNames = deploymentNamesRefDAO.getAllNamesByType(DeploymentNamesType.VM_NAME);
        Set<String> allVmNames = new HashSet<>();
        if (reservedVMNames != null) {
            allVmNames.addAll(reservedVMNames);
        }

        for (ServiceTemplateComponent component : serviceTemplate.getComponents()) {
            if (component.getType() != ServiceTemplateComponentType.VIRTUALMACHINE)
                continue;

            for (ServiceTemplateCategory resource : component.getResources()) {
                for (ServiceTemplateSetting param : resource.getParameters()) {
                    if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VM_GENERATE_NAME_ID.equals(param.getId())) {
                        if (param.getValue() != null && param.getValue().equals("true")) {
                            ServiceTemplateSetting vmNameTemplateSetting = component.getTemplateSetting(
                                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VM_NAME_TEMPLATE_ID);
                            String vmNameTemplate;
                            ServiceTemplateSetting vmNameSetting = component
                                    .getTemplateSetting(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VM_NAME);
                            if (vmNameSetting == null) {
                                logger.error("Cannot find VM Name setting in the service template for component = "
                                        + component.getAsmGUID());
                                throw new AsmManagerRuntimeException(
                                        "Cannot find VM Name setting in the service template for component = "
                                                + component.getAsmGUID());
                            }

                            if (StringUtils.isEmpty(vmNameSetting.getValue())) {
                                if (vmNameTemplateSetting != null
                                        && StringUtils.isNotEmpty(vmNameTemplateSetting.getValue())) {
                                    vmNameTemplate = vmNameTemplateSetting.getValue();
                                } else {
                                    logger.error(
                                            "Cannot find VM Name template setting in the service template for component = "
                                                    + component.getAsmGUID());
                                    throw new AsmManagerRuntimeException(
                                            "Cannot find VM Name template setting in the service template for component = "
                                                    + component.getAsmGUID());

                                }

                                vmNameTemplate = HostnameUtil.generateNameFromNumTemplate(vmNameTemplate,
                                        allVmNames);

                                // only check for dups
                                if (!allVmNames.add(vmNameTemplate)) {
                                    logger.error(
                                            "Duplicate generated hostname: " + vmNameTemplateSetting.getValue());
                                    throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                                            AsmManagerMessages.duplicateHostname(vmNameTemplate));
                                } else {
                                    vmNameSetting.setValue(vmNameTemplate);
                                    allVmNames.add(vmNameTemplate);
                                }
                            }

                            // last minute check
                            if (!ASMCommonsUtils.isValidVmName(vmNameSetting.getValue())) {
                                logger.error("Invalid generated vmname: " + vmNameSetting.getValue());
                                throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                                        AsmManagerMessages.invalidVmName(vmNameSetting.getValue()));
                            }
                        }
                    }

                }
            }
        }
    }

    private void processStorageVolumes(Deployment deployment) {
        ServiceTemplate serviceTemplate = deployment.getServiceTemplate();
        List<String> reservedNames = deploymentNamesRefDAO
                .getAllNamesByType(DeploymentNamesType.STORAGE_VOLUME_NAME);
        Set<String> allNames = new HashSet<>();
        if (reservedNames != null) {
            allNames.addAll(reservedNames);
        }

        for (ServiceTemplateComponent component : serviceTemplate.getComponents()) {
            if (!ServiceTemplateComponent.ServiceTemplateComponentType.STORAGE.equals(component.getType()))
                continue;

            for (ServiceTemplateCategory resource : component.getResources()) {
                for (ServiceTemplateSetting param : resource.getParameters()) {
                    if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_TITLE_ID.equals(param.getId())) {
                        if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_AUTOGENERATE
                                .equals(param.getValue())) {
                            ServiceTemplateSetting nameTemplateSetting = resource
                                    .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_TEMPLATE);
                            String nameTemplate;
                            ServiceTemplateSetting nameSetting = resource
                                    .getParameter(ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_GENERATED);
                            // only generate if empty
                            if (StringUtils.isEmpty(nameSetting.getValue())) {
                                if (nameTemplateSetting != null
                                        && StringUtils.isNotEmpty(nameTemplateSetting.getValue())) {
                                    nameTemplate = nameTemplateSetting.getValue();
                                } else {
                                    String err = "Cannot find volume name template setting in the service template for component = "
                                            + component.getAsmGUID();
                                    logger.error(err);
                                    throw new AsmManagerRuntimeException(err);
                                }

                                // same logic as for VM names autogenerator
                                nameTemplate = HostnameUtil.generateNameFromNumTemplate(nameTemplate, allNames);

                                // only check for dups
                                if (!allNames.add(nameTemplate)) {
                                    logger.error(
                                            "Duplicate generated volume name: " + nameTemplateSetting.getValue());
                                    throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                                            AsmManagerMessages.duplicateVolumeName(nameTemplate));
                                } else {
                                    nameSetting.setValue(nameTemplate);
                                    nameSetting.setHideFromTemplate(false);
                                    allNames.add(nameTemplate);
                                }
                            }
                        } else if (ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_OPTION_CREATE_DEPLOYMENT
                                .equals(param.getValue())) {
                            // change visibility for deployent time parameters - otherwise they won't show up in service details
                            ServiceTemplateSetting nameSetting = resource.getParameter(
                                    ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VOLUME_NAME_NEW_AT_DEPLOYMENT);
                            nameSetting.setHideFromTemplate(false);
                        }
                    }
                }
            }
        }
    }

    @Override
    public Deployment migrateServerComponent(String serviceId, String componentId) throws WebApplicationException {
        return migrateDeploymentComponent(serviceId, null, componentId, null, false);
    }

    /**
     * Returns a Deployment that is populated based on the data requested in the ServiceDefinition from a brownfield
     * environment.
     * 
     * @param serviceDefinition definition of the service that will be queried and created (if possible)
     */
    @Override
    public Deployment defineService(ServiceDefinition serviceDefinition) {
        return BrownfieldUtil.getInstance().defineService(serviceDefinition);
    }

    /**
     * Identifies the differences between the existing service in ASM and a new Brownfield discovery and returns a 
     * deployment that captures the differences.  New components are added to the template.  All of the Devices will
     * have a BrownfieldStatus that accurately represents the status with relation of the new components and components
     * that are part of the existing service in ASM. 
     * 
     * @see com.dell.asm.asmcore.asmmanager.client.deployment.BrownfieldStatus
     * 
     * @param serviceId the id of the existing Brownfield service in ASM.
     */
    @Override
    public Deployment defineServiceDiff(String serviceId) throws WebApplicationException {

        Deployment currentService = this.getDeployment(serviceId);
        return BrownfieldUtil.getInstance().defineServiceDiff(currentService);
    }

    /**
     * Wrapper for asm_depployer call to get)_server_info.
     * Returns Port View topology for given service and server.
     * @param serviceId
     * @param serverComponentId
     * @return
     * @throws WebApplicationException
     */
    @Override
    public ServerNetworkObjects getServerNetworkObjects(String serviceId, String serverComponentId)
            throws WebApplicationException {

        // Verify the User hass access
        this.checkUserPermission(serviceId);

        try {
            return getAsmDeployerProxy().getServerNetworkObjects(serviceId, serverComponentId);
        } catch (WebApplicationException wex) {
            logger.error("asm_deployer get_server_info failed", wex);
            throw new LocalizedWebApplicationException(Response.Status.INTERNAL_SERVER_ERROR,
                    AsmManagerMessages.internalError());
        }
    }

    // Checks to see if the user has access to the given deployment and throws an error if the user does not have access
    private void checkUserPermission(String deploymentId) {
        try {
            DeploymentEntity deploymentEntity = deploymentDAO.getDeployment(deploymentId, DeploymentDAO.NONE);
            if (deploymentEntity == null) {
                EEMILocalizableMessage msg = AsmManagerMessages.deploymentNotFound(deploymentId);
                throw new LocalizedWebApplicationException(Response.Status.NOT_FOUND, msg);
            }

            this.checkUserPermission(deploymentEntity);
        } catch (LocalizedWebApplicationException e) {
            logger.error("LocalizedWebApplicationException while getting Deployment with ID " + deploymentId, e);
            throw e;
        } catch (Exception e) {
            logger.error("Exception while getting Deployment with ID " + deploymentId, e);
            throw new LocalizedWebApplicationException(Response.Status.INTERNAL_SERVER_ERROR,
                    AsmManagerMessages.internalError());
        }
    }

    private void checkUserPermission(DeploymentEntity deploymentEntity) {

        User currentUser = this.asmManagerUtil.getCurrentUser(this.servletRequest);
        if (!checkUserPermissions(deploymentEntity, currentUser)) {
            logger.debug("Refused access to deployment ID=" + deploymentEntity.getId() + " for user "
                    + asmManagerUtil.getUserId() + " because of lack of permissions");
            throw new LocalizedWebApplicationException(Response.Status.NOT_FOUND,
                    AsmManagerMessages.deploymentNotFound(deploymentEntity.getId()));
        }
    }

    /* (non-Javadoc)
     * @see com.dell.asm.asmcore.asmmanager.client.deployment.IDeploymentService#getDeploymentsForNetworkId(java.lang.String)
     */
    @Override
    public Deployment[] getDeploymentsForNetworkId(String networkId) throws WebApplicationException {
        logger.debug("Get Deployments for NetworkId: " + networkId);
        ArrayList<Deployment> deploymentsList = new ArrayList<Deployment>();

        if (networkId == null) {
            throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                    AsmManagerMessages.invalidParam(networkId));
        }

        List<DeploymentEntity> deploymentEntities = this.deploymentDAO.getAllDeployment(DeploymentDAO.NONE);
        User currentUser = this.asmManagerUtil.getCurrentUser(this.servletRequest);

        deploymentLoop: for (DeploymentEntity deploymentEntity : deploymentEntities) {
            ServiceTemplate serviceTemplate = MarshalUtil.unmarshal(ServiceTemplate.class,
                    deploymentEntity.getMarshalledTemplateData());
            Set<String> networkIds = ServiceTemplateClientUtil.getNetworkIds(serviceTemplate);

            for (String networkIdToMatch : networkIds) {
                if (networkId.equals(networkIdToMatch)) {
                    deploymentsList.add(this.entityToView(deploymentEntity, currentUser));
                    continue deploymentLoop;
                }
            }
        }

        return deploymentsList.toArray(new Deployment[deploymentsList.size()]);
    }

    @Override
    public Response deleteUsers(List<String> userIds) throws WebApplicationException {
        if (userIds == null || userIds.size() <= 0) {
            throw new LocalizedWebApplicationException(Response.Status.BAD_REQUEST,
                    AsmManagerMessages.invalidParam("userIds"));
        }
        Set<String> userIdsSet = new HashSet<>(userIds);
        List<DeploymentEntity> deploymentEntities = deploymentDAO.getDeploymentsForUserIds(userIdsSet);
        if (deploymentEntities != null && deploymentEntities.size() > 0) {
            for (DeploymentEntity entity : deploymentEntities) {
                if (entity.getAssignedUserList() != null && entity.getAssignedUserList().size() > 0) {
                    boolean updateEntity = false;
                    Set<DeploymentUserRefEntity> updatedUsers = new HashSet<>();
                    for (DeploymentUserRefEntity user : entity.getAssignedUserList()) {
                        if (userIdsSet.contains(Long.toString(user.getUserId()))) {
                            updateEntity = true;
                        } else {
                            updatedUsers.add(user);
                        }
                    }
                    if (updateEntity) {
                        entity.setAssignedUserList(updatedUsers);
                        try {
                            deploymentDAO.updateDeployment(entity);
                        } catch (LocalizedWebApplicationException e) {
                            logger.error(
                                    "LocalizedWebApplicationException while updating Deployment " + entity.getId(),
                                    e);
                            throw e;
                        } catch (Exception e) {
                            logger.error("Exception while updating Deployment " + entity.getId(), e);
                            throw new LocalizedWebApplicationException(Response.Status.INTERNAL_SERVER_ERROR,
                                    AsmManagerMessages.internalError());
                        }
                    }
                }
            }
        }
        return Response.noContent().build();
    }

    public static Map<String, Set<String>> parseUsedDeploymentNames(ServiceTemplate serviceTemplate) {
        Map<String, Set<String>> usedDeploymentNames = new HashMap<>();

        Set<String> vmNames = new HashSet<>();
        Set<String> hostNames = new HashSet<>();
        Set<String> storageNames = new HashSet<>();

        if (serviceTemplate.getComponents() != null) {
            for (ServiceTemplateComponent component : serviceTemplate.getComponents()) {
                switch (component.getType()) {
                case VIRTUALMACHINE:
                    ServiceTemplateSetting vmNameSetting = component.getParameter(
                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VM_RESOURCE,
                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VM_NAME);
                    if (vmNameSetting == null) { // means there is no vm for vcenter, so try hyperv now
                        vmNameSetting = component.getParameter(
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_HV_VM_RESOURCE,
                                ServiceTemplateSettingIDs.SERVICE_TEMPLATE_VM_NAME);
                    }

                    if (vmNameSetting != null) {
                        if (StringUtils.isNotBlank(vmNameSetting.getValue())) {
                            // keep track of duplicates
                            vmNames.add(vmNameSetting.getValue());
                        }
                        // we found the setting so we should break
                        break;
                    }
                    //Setting was not found so fall through to look for hostname.
                case SERVER:
                    ServiceTemplateSetting osHostNameSetting = component.getParameter(
                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_RESOURCE,
                            ServiceTemplateSettingIDs.SERVICE_TEMPLATE_SERVER_OS_HOSTNAME_ID);
                    if (osHostNameSetting != null && StringUtils.isNotBlank(osHostNameSetting.getValue())
                            && !BrownfieldUtil.NOT_FOUND.equals(osHostNameSetting.getValue())) {
                        hostNames.add(osHostNameSetting.getValue());
                    }
                    break;
                case STORAGE:
                    for (String storageType : ServiceTemplateSettingIDs.SERVICE_TEMPLATE_STORAGE_RESOURCE_LIST) {
                        ServiceTemplateCategory storageCat = component.getTemplateResource(storageType);
                        if (storageCat != null && ServiceTemplateClientUtil.isNewStorageVolume(storageCat, true)) {
                            String volume = ServiceTemplateClientUtil.getVolumeNameForStorageComponent(storageCat);
                            if (StringUtils.isNotBlank(volume) && !BrownfieldUtil.NOT_FOUND.equals(volume)) {
                                storageNames.add(volume);
                                break; // we can have only one volume per component
                            }
                        }
                    }
                    break;

                default:
                    break;
                }
            }
        }

        usedDeploymentNames.put(OS_HOST_NAMES, hostNames);
        usedDeploymentNames.put(VM_NAMES, vmNames);
        usedDeploymentNames.put(STORAGE_NAMES, storageNames);
        return usedDeploymentNames;
    }

    public static void updateDeploymentNameRefsOnDeployment(DeploymentEntity deploymentEntity,
            Map<String, Set<String>> usedDeploymentNames) {
        if (usedDeploymentNames != null) {
            Set<String> hostNames = usedDeploymentNames.get(OS_HOST_NAMES);
            Set<String> vmNames = usedDeploymentNames.get(VM_NAMES);
            Set<String> storageNames = usedDeploymentNames.get(STORAGE_NAMES);

            if ((hostNames != null && !hostNames.isEmpty()) || (vmNames != null && !vmNames.isEmpty())
                    || (storageNames != null && !storageNames.isEmpty())) {
                Map<String, DeploymentNamesRefEntity> usedHostNamesMap = new HashMap<>();
                Map<String, DeploymentNamesRefEntity> usedVMNamesMap = new HashMap<>();
                Map<String, DeploymentNamesRefEntity> usedVolumesMap = new HashMap<>();
                if (deploymentEntity.getNamesRefs() != null) {
                    for (DeploymentNamesRefEntity namesRefEntity : deploymentEntity.getNamesRefs()) {
                        switch (namesRefEntity.getType()) {
                        case VM_NAME:
                            usedVMNamesMap.put(namesRefEntity.getName(), namesRefEntity);
                            break;
                        case OS_HOST_NAME:
                            usedHostNamesMap.put(namesRefEntity.getName(), namesRefEntity);
                            break;
                        case STORAGE_VOLUME_NAME:
                            usedVolumesMap.put(namesRefEntity.getName(), namesRefEntity);
                            break;
                        }
                    }
                }

                Set<DeploymentNamesRefEntity> updatedNamesRefSet = new HashSet<>();

                if (hostNames != null && !hostNames.isEmpty()) {
                    final Set<String> usedHostNames = usedHostNamesMap.keySet();
                    for (String hostName : hostNames) {
                        if (usedHostNames.contains(hostName)) {
                            updatedNamesRefSet.add(usedHostNamesMap.get(hostName));
                        } else {
                            DeploymentNamesRefEntity entity = new DeploymentNamesRefEntity();
                            entity.setId(UUID.randomUUID().toString());
                            entity.setDeploymentId(deploymentEntity.getId());
                            entity.setType(DeploymentNamesType.OS_HOST_NAME);
                            entity.setName(hostName);
                            updatedNamesRefSet.add(entity);
                        }
                    }
                }

                if (vmNames != null && !vmNames.isEmpty()) {
                    final Set<String> usedVMNames = usedVMNamesMap.keySet();
                    for (String vmName : vmNames) {
                        if (usedVMNames.contains(vmName)) {
                            updatedNamesRefSet.add(usedVMNamesMap.get(vmName));
                        } else {
                            DeploymentNamesRefEntity entity = new DeploymentNamesRefEntity();
                            entity.setId(UUID.randomUUID().toString());
                            entity.setDeploymentId(deploymentEntity.getId());
                            entity.setType(DeploymentNamesType.VM_NAME);
                            entity.setName(vmName);
                            updatedNamesRefSet.add(entity);
                        }
                    }
                }

                if (storageNames != null && !storageNames.isEmpty()) {
                    final Set<String> usedVolumes = usedVolumesMap.keySet();
                    for (String volume : storageNames) {
                        if (usedVolumes.contains(volume)) {
                            updatedNamesRefSet.add(usedVolumesMap.get(volume));
                        } else {
                            DeploymentNamesRefEntity entity = new DeploymentNamesRefEntity();
                            entity.setId(UUID.randomUUID().toString());
                            entity.setDeploymentId(deploymentEntity.getId());
                            entity.setType(DeploymentNamesType.STORAGE_VOLUME_NAME);
                            entity.setName(volume);
                            updatedNamesRefSet.add(entity);
                        }
                    }
                }
                deploymentEntity.setNamesRefs(updatedNamesRefSet);
            }
        }
    }

    public MigrationDeviceUtils getMigrationDeviceUtils() {
        return migrationDeviceUtils;
    }

    public void setMigrationDeviceUtils(MigrationDeviceUtils migrationDeviceUtils) {
        this.migrationDeviceUtils = migrationDeviceUtils;
    }

    /**
     * Returns the FirmwareComplianceReport for the given deployment/serviceId.
     */
    @Override
    public FirmwareComplianceReport[] getFirmwareComplianceReportsForDevicesInDeployment(String deploymentId)
            throws WebApplicationException {

        FirmwareComplianceReport[] firmwareComplianceReports = null;

        // Load a Deployment throw error if not found
        DeploymentEntity deploymentEntity;
        try {
            deploymentEntity = deploymentDAO.getDeployment(deploymentId, DeploymentDAO.ALL_ENTITIES);
            if (deploymentEntity == null) {
                EEMILocalizableMessage msg = AsmManagerMessages.deploymentNotFound(deploymentId);
                throw new LocalizedWebApplicationException(Response.Status.NOT_FOUND, msg);
            }
        } catch (LocalizedWebApplicationException e) {
            logger.error("LocalizedWebApplicationException while getting Deployment with ID " + deploymentId, e);
            throw e;
        } catch (Exception e) {
            logger.error("Exception while getting Deployment with ID " + deploymentId, e);
            throw new LocalizedWebApplicationException(Response.Status.INTERNAL_SERVER_ERROR,
                    AsmManagerMessages.internalError());
        }

        // Validate Security Access
        this.checkUserPermission(deploymentEntity);

        // Generate the Firmware Compliance Report
        try {
            firmwareComplianceReports = this.firmwareUtil
                    .getFirmwareComplianceReportsForDeployment(deploymentEntity);
        } catch (Exception ace) {
            logger.error("Error trying to generate firmware compliance reports for deployment with id: "
                    + deploymentEntity.getId(), ace);
            throw new LocalizedWebApplicationException(Response.Status.INTERNAL_SERVER_ERROR,
                    AsmManagerMessages.internalError());
        }

        return firmwareComplianceReports;
    }

    private CompliantState getCompliantState(DeploymentEntity deploymentEntity, DeviceInventoryEntity device) {
        CompliantState compliantState = CompliantState.COMPLIANT;

        // Compliance for shared Device's is not stored in the device_inventory table, instead it
        // must be loaded from the device_inventory_compliance_map table
        if (deploymentEntity.isManageFirmware() && device.getDeviceType().isSharedDevice()
                && deploymentEntity.getFirmwareRepositoryEntity() != null) {
            // Load the device's compliance status
            DeviceInventoryComplianceEntity dice = this.deviceInventoryComplianceDAO.findDeviceInventoryCompliance(
                    device.getRefId(), deploymentEntity.getFirmwareRepositoryEntity().getId());
            if (dice != null) {
                compliantState = dice.getCompliance();
            }
        } else {
            compliantState = CompliantState.fromValue(device.getCompliant());
        }

        return compliantState;
    }

}