/* * Copyright (c) 2008-2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.plugins.common; import com.emc.storageos.db.client.model.StorageSystem.Discovery_Namespaces; import com.emc.storageos.plugins.AccessProfile; import com.emc.storageos.plugins.BaseCollectionException; import com.emc.storageos.plugins.common.commandgenerator.Command; import com.emc.storageos.plugins.common.commandgenerator.CommandGenerator; import com.emc.storageos.plugins.common.domainmodel.Namespace; import com.emc.storageos.plugins.common.domainmodel.Operation; import com.emc.storageos.plugins.metering.smis.SMIPluginException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.cim.CIMArgument; import javax.cim.CIMProperty; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * SMIExecutor- responsible for executing SMICommands * */ public abstract class Executor { /** * Logger. */ protected static final Logger _LOGGER = LoggerFactory.getLogger(Executor.class); private static final String NEWLINE = "\n"; private static final String SEMICOLON = "; "; private static final String TAB = "\t"; /** * Discover Util. */ protected Util _util; /** * Command Objects. */ protected List<Command> _commandObjects; protected CommandGenerator _generator; /** * Generator. */ private ExecutorService execService = null; /** * keyMap. */ protected Map<String, Object> _keyMap; public void setUtil(Util _util) { this._util = _util; } public Util getUtil() { return _util; } public void setKeyMap(Map<String, Object> _keyMap) { this._keyMap = _keyMap; } public Map<String, Object> getKeyMap() { return _keyMap; } public void setGenerator(CommandGenerator _generator) { this._generator = _generator; } public CommandGenerator getGenerator() { return _generator; } public Executor() { execService = Executors.newFixedThreadPool(10); } public ExecutorService getExecService() { return execService; } /** * This execute method is common for all the plugins. It checks whether each * operation in Domain Logic has to get executed, then execute and move it * to processor.It loops through each operation in Domain Logic and sends to * executeoperation(), where the actual conversion of operation to Command * happens and each Command gets executed. The List of Result Objects will * then be sent to the Processor. * * @throws BaseCollectionException * ex. */ public void execute(Namespace ns) throws BaseCollectionException { assert ns != null; for (Object operationobj : ns.getOperations()) { Operation operation = (Operation) operationobj; executeOperation(operation); } } /** * Move the result to Processor. Processor can be of type CIMProcessor, * DirectorMetrics Apply different types of Decorators above the processed * Result Multiple Decorators can be applied on the processed Result. * Multiple Processors can be applied on the result got from Executor. * * @param operation * : Domain Logic operation. * @param result * : Result Object got from 3rd party instance. * @throws BaseCollectionException * ex. */ protected void processResult(final Operation operation, final Object result, final Command commandObj) throws BaseCollectionException { Processor _processor = null; // processor is being shared across multiple Threads in case of parallel // processing. // But still, processResult is not synchronized intentionally, as I want // multiple Threads to complete its job without waiting. // Things which get shared across threads is only the ConcurrentMap, // hence haven't made it synchronized. _processor = operation.getProcessor(); if (null != _processor) { List<Object> argsList = new ArrayList<Object>(); argsList.add(Util.normalizedReadArgs(_keyMap, commandObj.retreiveArguments())); argsList.add(commandObj.getCommandIndex()); _processor.setPrerequisiteObjects(argsList); _processor.processResult(operation, result, _keyMap); } else { _LOGGER.debug("No Processors found to execute. "); } } /** * Every Plugin's Executor should override this method, and throw their own * Custom Exceptions with Messages. * * @param e * @throws BaseCollectionException */ protected abstract void customizeException(Exception e, Operation operation) throws BaseCollectionException; /** * Execute the Operation defined in Domain Logic XML. Use Generator to * return Command Objects for an Operation. Then execute them either in a * multi-threaded fashion or singleThreaded. * * @param operation * @throws BaseCollectionException */ private void executeOperation(Operation operation) throws BaseCollectionException { try { if (!isSupportedOperation(operation)) { _LOGGER.info("Filtered the operation {} as per instructions", operation.getMessage()); return; } _LOGGER.info(null == operation.getMessage() ? "START Executing operation" : "START :" + operation.getMessage()); _commandObjects = _generator.returnCommandObjects(operation, _keyMap); // only sequential processing allowed. also avoiding too many calls to the Provider at // the same time. for (Command commandObj : _commandObjects) { printArgs(commandObj); Object resultObj = null; try { resultObj = commandObj.execute(); processResult(operation, resultObj, commandObj); } catch (Exception e) { _LOGGER.error("Execution failed for :", e); // We do not want 'Provider/Firmware Not Supported Error' to get suppressed. check and throw again. if (e instanceof SMIPluginException) { int errorCode = ((SMIPluginException) e).getErrorCode(); if (errorCode == SMIPluginException.ERRORCODE_PROVIDER_NOT_SUPPORTED || errorCode == SMIPluginException.ERRORCODE_FIRMWARE_NOT_SUPPORTED || errorCode == SMIPluginException.ERRORCODE_OPERATIONFAILED) { throw e; } } } } } catch (final Exception e) { _LOGGER.error("Operation Execution failed : ", e); customizeException(e, operation); } _LOGGER.debug(null == operation.getMessage() ? "END Executing operation" : "END :" + operation.getMessage()); } /** * Method to print arguments for debug purpose * * @param commandObject */ public void printArgs(Command commandObject) { try { StringBuilder logMessage = new StringBuilder(); logMessage.append(NEWLINE).append("{"); for (Object obj : commandObject.retreiveArguments()) { if (null == obj) { logMessage.append("NULL").append(SEMICOLON); } else { if (obj instanceof CIMArgument<?>[]) { logMessage.append("Input CIMArgument Array : {"); CIMArgument<?>[] outputArguments = (CIMArgument<?>[]) obj; for (CIMArgument<?> outArg : outputArguments) { if (null != outArg) { logMessage.append(TAB); logMessage .append("Name:") .append(null == outArg.getName() ? "unknown" : outArg.getName()).append(SEMICOLON); logMessage .append("DataType:") .append(null == outArg.getDataType() ? "unknown" : outArg.getDataType()).append(SEMICOLON); logMessage .append("Value :") .append(null == outArg.getValue() ? "unknown" : outArg.getValue()).append(SEMICOLON); } else { logMessage.append("NULL").append(SEMICOLON); } } logMessage.append("}").append(SEMICOLON).append(NEWLINE); } else if (obj instanceof CIMProperty<?>[]) { logMessage.append(NEWLINE).append("Input CIMProperty Array : {"); CIMProperty<?>[] args = (CIMProperty<?>[]) obj; for (CIMProperty<?> p : args) { if (null != p) { logMessage .append("Name:") .append(null == p.getName() ? "unknown" : p .getName()).append(SEMICOLON); logMessage .append("DataType:") .append(null == p.getDataType() ? "unknown" : p .getDataType()).append(SEMICOLON); logMessage .append("Value :") .append(null == p.getValue() ? "unknown" : p .getValue()).append(SEMICOLON); } } logMessage.append("}").append(SEMICOLON).append(NEWLINE); } else if (obj instanceof String[]) { logMessage.append(Arrays.toString((String[]) obj)).append( SEMICOLON); } else { logMessage.append(obj.toString()).append(SEMICOLON); } } } logMessage.append("}"); _LOGGER.debug(logMessage.toString()); } catch (Exception e) { _LOGGER.debug("Logging operations failed", e); } } /** * return true always to support other device types. * * @param operation * @return */ protected boolean isSupportedOperation(Operation operation) { return true; } }