/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.intel.mtwilson.as.business; import com.intel.mountwilson.as.common.ASConfig; import com.intel.mountwilson.as.common.ASException; import com.intel.mtwilson.as.ASComponentFactory; import com.intel.mtwilson.datatypes.HostConfigData; import com.intel.mtwilson.datatypes.HostConfigDataList; import com.intel.mtwilson.i18n.ErrorCode; import com.intel.mtwilson.datatypes.HostConfigResponse; import com.intel.mtwilson.datatypes.HostConfigResponseList; import com.intel.mtwilson.datatypes.HostResponse; import com.intel.mtwilson.datatypes.TxtHost; import com.intel.mtwilson.datatypes.TxtHostRecord; import com.intel.mtwilson.datatypes.TxtHostRecord; import com.intel.mtwilson.datatypes.TxtHostRecordList; import com.intel.mtwilson.datatypes.TxtHostRecordList; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author ssbangal */ public class BulkHostMgmtBO { private Logger log = LoggerFactory.getLogger(getClass()); private HostBO hostBO = ASComponentFactory.getHostBO(); private int timeout; private static ExecutorService scheduler = Executors.newFixedThreadPool(ASConfig.getConfiguration().getInt("mtwilon.bulkmgmt.threads.max", 32)); // bug #503 move thread pool to static so multiple requests do not overload it; public BulkHostMgmtBO() { timeout = ASConfig.getConfiguration().getInt("com.intel.mountwilson.as.hostmgmt.hostTimeout", 600); } public BulkHostMgmtBO(int timeout) { this.timeout = timeout; } public HostConfigResponseList addHosts(TxtHostRecordList hostRecords) { // Set the updateHost flag to false since we are adding the hosts; return addUpdateHosts(convertToHostConfigDataList(hostRecords), false); } public HostConfigResponseList updateHosts(TxtHostRecordList hostRecords) { // Set the updateHost flag to true since we are adding the hosts; return addUpdateHosts(convertToHostConfigDataList(hostRecords), true); } public HostConfigResponseList addHosts(HostConfigDataList hostRecords) { // Set the updateHost flag to false since we are adding the hosts; return addUpdateHosts(hostRecords, false); } public HostConfigResponseList updateHosts(HostConfigDataList hostRecords) { // Set the updateHost flag to true since we are adding the hosts; return addUpdateHosts(hostRecords, true); } private HostConfigDataList convertToHostConfigDataList(TxtHostRecordList hostRecords) { HostConfigDataList wrapperList = new HostConfigDataList(); for (TxtHostRecord hostRecord : hostRecords.getHostRecords()) { HostConfigData wrapperHostRecord = new HostConfigData(); // Explicity set the BIOS and VMM WhiteList targets to NULL so that we can use this // value to determine whether the user had passed in just the TXTHostRecord or the // complete Configuration record wrapperHostRecord.setBiosWLTarget(null); wrapperHostRecord.setVmmWLTarget(null); wrapperHostRecord.setTxtHostRecord(hostRecord); wrapperList.getHostRecords().add(wrapperHostRecord); } return wrapperList; } /** * This function handles multithread calls for both add and update host functionalities. * @param hostRecords - List of the hosts that need to be added/updated * @param updateHost - flag indicating whether the hosts should be added or updated. * @return */ private HostConfigResponseList addUpdateHosts(HostConfigDataList hostRecords, boolean updateHost) { HostConfigResponseList hostResponses = new HostConfigResponseList(); ArrayList<Future<?>> taskStatus = new ArrayList<Future<?>>(); Set<HostMgmt> tasks = new HashSet<HostMgmt>(); try { for (HostConfigData hostRecord : hostRecords.getHostRecords()) { HostMgmt task = new HostMgmt(hostBO, hostRecord, updateHost); tasks.add(task); Future<?> status = scheduler.submit(task); taskStatus.add(status); } // The purpose of this below loop is to ensure that all the threads have completed processing. // If in case we can an exception from any one of them, we will log the same and continue. Since // we submitted the Runnable tasks we won't get back the status in this loop. for (Future<?> status : taskStatus) { try { status.get(timeout, TimeUnit.SECONDS); } catch (Exception ex) { log.error("Exception while retrieving the status of the task. {}.", ex.getMessage()); } } // Retrieve the status from all the threads and return back to the user. for (HostMgmt task : tasks) { if (task.getResult() == null) { hostResponses.getHostRecords().add(task.getTimeoutResult()); } else { hostResponses.getHostRecords().add(task.getResult()); } } return hostResponses; } catch (Exception ex) { // throw new ASException(ex); // Bug: 1038 - prevent leaks in error messages to client log.error("Error during bulk host registration.", ex); throw new ASException(ErrorCode.AS_BULK_REGISTER_HOST_ERROR, ex.getClass().getSimpleName()); } } private class HostMgmt implements Runnable { private HostBO dao; private HostConfigData hostObj; private HostResponse result; private String hostName; private boolean isError = false; private boolean updateHost = false; public HostMgmt(HostBO dao, HostConfigData hostObj, boolean updateHost) { this.dao = dao; this.hostObj = hostObj; this.hostName = hostObj.getTxtHostRecord().HostName; this.updateHost = updateHost; } @Override public void run() { if (isError()) { return; } try { if (!updateHost) result = dao.addHostByFindingMLE(hostObj); else result = dao.updateHostByFindingMLE(hostObj); } catch (ASException e) { isError = true; result = new HostResponse(); result.setErrorCode(e.getErrorCode().toString()); result.setErrorMessage(e.getErrorMessage()); } catch (Exception e) { isError = true; result = new HostResponse(ErrorCode.AS_REGISTER_HOST_ERROR, String.format(ErrorCode.AS_REGISTER_HOST_ERROR.getMessage(), e.getClass().getSimpleName())); } } public boolean isError() { return isError; } public HostConfigResponse getResult() { HostConfigResponse hostResponse = new HostConfigResponse(); hostResponse.setHostName(hostName); hostResponse.setErrorCode(result.getErrorCodeEnum()); if (result.getErrorCodeEnum() == ErrorCode.OK) { hostResponse.setStatus(Boolean.toString(true)); hostResponse.setErrorMessage(""); } else { hostResponse.setStatus(Boolean.toString(false)); hostResponse.setErrorMessage(result.getErrorMessage()); } return hostResponse; } public HostConfigResponse getTimeoutResult() { HostConfigResponse hostResponse = new HostConfigResponse(); hostResponse.setHostName(hostName); hostResponse.setErrorCode(ErrorCode.AS_ASYNC_TIMEOUT); hostResponse.setStatus(Boolean.toString(false)); hostResponse.setErrorMessage("Exceeded timeout of " + timeout + " seconds"); return hostResponse; } } }