public class AcceptanceTestContext {

	private Logger logger = Logger.getLogger(AcceptanceTestContext.class.getSimpleName());
	
	public final static String
	    PROP_SOAP_ACTION_11 = "SOAPAction",
	    PROP_SOAP_ACTION_12 = "action=",
	    PROP_CONTENT_TYPE = "Content-Type",
	    PROP_CONTENT_LENGTH = "Content-Length",
	    PROP_AUTH = "Authorization",
	    PROP_PROXY_AUTH = "Proxy-Authorization",
	    PROP_PROXY_CONN = "Proxy-Connection",
	    PROP_KEEP_ALIVE = "Keep-Alive",
	    PROP_BASIC_AUTH = "Basic",
	    PROP_DELIMITER = "; ";
	
	public final static String
	    SOAP_1_1_NAMESPACE = "http://schemas.xmlsoap.org/soap/envelope/",
	    SOAP_1_2_NAMESPACE = "http://www.w3.org/2003/05/soap-envelope";
	
	public final static String
	    MIMETYPE_TEXT_HTML = "text/html",
	    MIMETYPE_TEXT_PLAIN = "text/plain",
	    MIMETYPE_TEXT_XML = "text/xml",
	    MIMETYPE_APPLICATION_XML = "application/soap+xml";
	
	public static final String GATF_SERVER_LOGS_API_FILE_NM = "gatf-logging-api-int.xml";
	
	private final Map<String, List<TestCase>> relatedTestCases = new HashMap<String, List<TestCase>>();
	
	private final Map<String, String> httpHeaders = new HashMap<String, String>();

	private ConcurrentHashMap<Integer, String> sessionIdentifiers = new ConcurrentHashMap<Integer, String>();
	
	private final Map<String, String> soapEndpoints = new HashMap<String, String>();
	
	private final Map<String, Document> soapMessages = new HashMap<String, Document>();
	
	private final Map<String, String> soapStrMessages = new HashMap<String, String>();
	
	private final Map<String, String> soapActions = new HashMap<String, String>();
	
	private final WorkflowContextHandler workflowContextHandler = new WorkflowContextHandler();
	
	private List<TestCase> serverLogsApiLst = new ArrayList<TestCase>();
	
	private GatfExecutorConfig gatfExecutorConfig;
	
	private ClassLoader projectClassLoader;
	
	private Map<String, Method> prePostTestCaseExecHooks = new HashMap<String, Method>();
	
	public static final UrlValidator URL_VALIDATOR = new UrlValidator(new String[]{"http","https"}, UrlValidator.ALLOW_LOCAL_URLS);
	
	public static boolean isValidUrl(String url) {
		if(!URL_VALIDATOR.isValid(url)) {
			if(url.startsWith("host.docker.internal")) {
				url = url.replace("host.docker.internal", "");
				if(url.length()>0 && url.charAt(0)==':') {
					url = url.substring(1);
				}
				if(url.indexOf("/")!=-1) {
					url = url.substring(0, url.indexOf("/"));
				}
				try {
					Integer.parseInt(url);
				} catch (Exception e) {
					return false;
				}
			}
		}
		return true;
	}
	
	public static void setCorsHeaders(Response response) {
		if(Boolean.FALSE.toString().equalsIgnoreCase(System.getenv("cors.enabled")) || Boolean.FALSE.toString().equalsIgnoreCase(System.getProperty("cors.enabled"))) {
		} else {
			response.setHeader("Access-Control-Allow-Origin", "*");
			response.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
			response.setHeader("Access-Control-Allow-Headers", "*");
		}
	}
	
	public ClassLoader getProjectClassLoader() {
		return projectClassLoader;
	}

	private final Map<String, List<Map<String, String>>> providerTestDataMap = new HashMap<String, List<Map<String,String>>>();
	private final Map<String, String> fileProviderStateMap = new HashMap<String, String>();
	
	public List<Map<String, String>> getProviderTestDataMap(String providerName) {
	    if(liveProviders.containsKey(providerName))
        {
            GatfTestDataProvider provider = liveProviders.get(providerName);
            return getProviderData(provider, null);
        }
	    else 
	    {
	        return providerTestDataMap.get(providerName);
	    }
	}
	
	public String getFileProviderHash(String name) {
	    if(!fileProviderStateMap.containsKey(name)) {
	        return fileProviderStateMap.get(name);
	    }
	    return null;
	}
	
	public void newProvider(String name) {
	    if(!providerTestDataMap.containsKey(name)) {
	        providerTestDataMap.put(name, new ArrayList<Map<String,String>>());
	    }
	}
	
	private final Map<String, TestDataSource> dataSourceMap = new HashMap<String, TestDataSource>();
	
	private final Map<String, TestDataSource> dataSourceMapForProfiling = new HashMap<String, TestDataSource>();
	
	private final Map<String, GatfTestDataSourceHook> dataSourceHooksMap = new HashMap<String, GatfTestDataSourceHook>();

	private final SingleTestCaseExecutor singleTestCaseExecutor = new SingleTestCaseExecutor();
	
	private final ScenarioTestCaseExecutor scenarioTestCaseExecutor = new ScenarioTestCaseExecutor();
	
	private final PerformanceTestCaseExecutor performanceTestCaseExecutor = new PerformanceTestCaseExecutor();
	
	private final Map<String, GatfTestDataProvider> liveProviders = new HashMap<String, GatfTestDataProvider>();

	public SingleTestCaseExecutor getSingleTestCaseExecutor() {
		return singleTestCaseExecutor;
	}

	public ScenarioTestCaseExecutor getScenarioTestCaseExecutor() {
		return scenarioTestCaseExecutor;
	}

	public PerformanceTestCaseExecutor getPerformanceTestCaseExecutor() {
		return performanceTestCaseExecutor;
	}

	public AcceptanceTestContext(){}
	
	public AcceptanceTestContext(GatfExecutorConfig gatfExecutorConfig, ClassLoader projectClassLoader)
	{
		this.gatfExecutorConfig = gatfExecutorConfig;
		this.projectClassLoader = projectClassLoader;
		getWorkflowContextHandler().init();
	}
	
	public AcceptanceTestContext(DistributedAcceptanceContext dContext, ClassLoader projectClassLoader)
	{
        this.projectClassLoader = projectClassLoader;
		this.gatfExecutorConfig = dContext.getConfig();
		this.httpHeaders.putAll(dContext.getHttpHeaders());
		this.soapEndpoints.putAll(dContext.getSoapEndpoints());
		this.soapActions.putAll(dContext.getSoapActions());
		try {
			if(dContext.getSoapMessages()!=null) {
				DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
				DocumentBuilder db = dbf.newDocumentBuilder();
				for (Map.Entry<String, String> soapMsg : dContext.getSoapMessages().entrySet()) {
					Document soapMessage = db.parse(new ByteArrayInputStream(soapMsg.getValue().getBytes()));
					this.soapMessages.put(soapMsg.getKey(), soapMessage);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			// TODO: handle exception
		}
		getWorkflowContextHandler().init();
	}
	
	public GatfExecutorConfig getGatfExecutorConfig() {
		return gatfExecutorConfig;
	}

	public void setGatfExecutorConfig(GatfExecutorConfig gatfExecutorConfig) {
		this.gatfExecutorConfig = gatfExecutorConfig;
	}

	public ConcurrentHashMap<Integer, String> getSessionIdentifiers() {
		return sessionIdentifiers;
	}

	public void setSessionIdentifiers(
			ConcurrentHashMap<Integer, String> sessionIdentifiers) {
		this.sessionIdentifiers = sessionIdentifiers;
	}

	public void setSessionIdentifier(String identifier, TestCase testCase) {
		Integer simulationNumber = testCase.getSimulationNumber();
		if(testCase.isServerApiAuth() || testCase.isServerApiTarget()) {
			simulationNumber = -1;
		} else if(testCase.isExternalApi()) {
			simulationNumber = -2;
		} else if(simulationNumber==null) {
			simulationNumber = 0;
		}
		sessionIdentifiers.put(simulationNumber, identifier);
	}
	
	public String getSessionIdentifier(TestCase testCase) {
		if(testCase.isServerApiAuth() || testCase.isServerApiTarget()) {
			return sessionIdentifiers.get(-1);
		}
		if(testCase.isExternalApi()) {
			return sessionIdentifiers.get(-2);
		}
		if(testCase.getSimulationNumber()!=null)
			return sessionIdentifiers.get(testCase.getSimulationNumber());
		
		return sessionIdentifiers.get(0);
	}
	
	public Map<String, String> getHttpHeaders() {
		return httpHeaders;
	}

	public Map<String, String> getSoapEndpoints() {
		return soapEndpoints;
	}

	public Map<String, Document> getSoapMessages() {
		return soapMessages;
	}

	public Map<String, String> getSoapActions() {
		return soapActions;
	}

	public WorkflowContextHandler getWorkflowContextHandler() {
		return workflowContextHandler;
	}
	
	@SuppressWarnings("rawtypes")
	public Class addTestCaseHooks(Method method) {
		Class claz = null;
		if(method!=null && Modifier.isStatic(method.getModifiers())) {
			
			Annotation preHook = method.getAnnotation(PreTestCaseExecutionHook.class);
            Annotation postHook = method.getAnnotation(PostTestCaseExecutionHook.class);
			
			if(preHook!=null)
			{
				PreTestCaseExecutionHook hook = (PreTestCaseExecutionHook)preHook;
				
				if(method.getParameterTypes().length!=1 || !method.getParameterTypes()[0].equals(TestCase.class))
				{
					logger.severe("PreTestCaseExecutionHook annotated methods should " +
							"confirm to the method signature - `public static void {methodName} (" +
							"TestCase testCase)`");
					return claz;
				}
				
				if(hook.value()!=null && hook.value().length>0)
				{
					for (String testCaseName : hook.value()) {
						if(testCaseName!=null && !testCaseName.trim().isEmpty())  {
							prePostTestCaseExecHooks.put("pre"+testCaseName, method);
						}
					}
				}
				else
				{
					prePostTestCaseExecHooks.put("preAll", method);
				}
				claz = method.getDeclaringClass();
			}
			if(postHook!=null)
			{
				PostTestCaseExecutionHook hook = (PostTestCaseExecutionHook)postHook;
				
				if(method.getParameterTypes().length!=1 || !method.getParameterTypes()[0].equals(TestCaseReport.class))
				{
					logger.severe("PostTestCaseExecutionHook annotated methods should " +
							"confirm to the method signature - `public static void {methodName} (" +
							"TestCaseReport testCaseReport)`");
					return claz;
				}
				
				if(hook.value()!=null && hook.value().length>0)
				{
					for (String testCaseName : hook.value()) {
						if(testCaseName!=null && !testCaseName.trim().isEmpty())  {
							prePostTestCaseExecHooks.put("post"+testCaseName, method);
						}
					}
				}
				else
				{
					prePostTestCaseExecHooks.put("postAll", method);
				}
				claz = method.getDeclaringClass();
			}
		}
		return claz;
	}
	
	public List<Method> getPrePostHook(TestCase testCase, boolean isPreHook) {
		List<Method> methods = new ArrayList<Method>();
		String hookKey = (isPreHook?"pre":"post") + testCase.getName();
		Method meth = prePostTestCaseExecHooks.get(hookKey);
		if(meth!=null)
			methods.add(meth);
		meth = prePostTestCaseExecHooks.get((isPreHook?"preAll":"postAll"));
		if(meth!=null)
			methods.add(meth);
		return methods;
	}
	
	public File getResourceFile(String filename) {
		File basePath = new File(gatfExecutorConfig.getTestCasesBasePath());
	    File testPath = new File(basePath, gatfExecutorConfig.getTestCaseDir());
	    File resource = new File(testPath, filename);
        if(!resource.exists()) {
            resource = new File(basePath, filename);
        }
		return resource;
	}
	
	public File getNewOutResourceFile(String filename) {
		File basePath = new File(gatfExecutorConfig.getOutFilesBasePath());
		File resource = new File(basePath, gatfExecutorConfig.getOutFilesDir());
		File file = new File(resource, filename);
		if(!file.exists()) {
			try {
				file.createNewFile();
			} catch (IOException e) {
			}
		}
		return file;
	}
	
	public File getOutDir() {
		File basePath = new File(gatfExecutorConfig.getOutFilesBasePath());
		File resource = new File(basePath, gatfExecutorConfig.getOutFilesDir());
		return resource;
	}
	
	public String getOutDirPath() {
		File basePath = new File(gatfExecutorConfig.getOutFilesBasePath());
		File resource = new File(basePath, gatfExecutorConfig.getOutFilesDir());
		return resource.getAbsolutePath();
	}
	
	public Map<String, List<TestCase>> getRelatedTestCases() {
		return relatedTestCases;
	}

	public static void removeFolder(File folder)
	{
		if(folder==null || !folder.exists())return;
		try {
			FileUtils.deleteDirectory(folder);
		} catch (IOException e) {
		}
	}
	
	public void validateAndInit(boolean flag) throws Exception
	{
		gatfExecutorConfig.validate();
		
		if(gatfExecutorConfig.getOutFilesBasePath()!=null)
		{
			File basePath = new File(gatfExecutorConfig.getOutFilesBasePath().trim());
			Assert.assertTrue("Invalid out files base path..", basePath.exists());
			gatfExecutorConfig.setOutFilesBasePath(basePath.getAbsolutePath());
		}
		else
		{
			File basePath = new File(System.getProperty("user.dir"));
			gatfExecutorConfig.setOutFilesBasePath(basePath.getAbsolutePath());
		}
		
		if(gatfExecutorConfig.getTestCasesBasePath()!=null)
		{
			File basePath = new File(gatfExecutorConfig.getTestCasesBasePath());
			Assert.assertTrue("Invalid test cases base path..", basePath.exists());
			gatfExecutorConfig.setTestCasesBasePath(basePath.getAbsolutePath());
		}
		else
		{
			File basePath = new File(System.getProperty("user.dir"));
			gatfExecutorConfig.setTestCasesBasePath(basePath.getAbsolutePath());
		}
		
		Assert.assertEquals("Testcase directory not found...", getResourceFile(gatfExecutorConfig.getTestCaseDir()).exists(), true);
		
		if(StringUtils.isNotBlank(gatfExecutorConfig.getBaseUrl()))
		{
			Assert.assertTrue("Base URL is not valid", AcceptanceTestContext.isValidUrl(gatfExecutorConfig.getBaseUrl()));
		}
		
		if(gatfExecutorConfig.getOutFilesDir()!=null && !gatfExecutorConfig.getOutFilesDir().trim().isEmpty())
		{
			try
			{
				if(gatfExecutorConfig.getOutFilesBasePath()!=null)
				{
					File basePath = new File(gatfExecutorConfig.getOutFilesBasePath());
					File resource = new File(basePath, gatfExecutorConfig.getOutFilesDir());
					if(flag)
					{
						removeFolder(resource);
						File nresource = new File(basePath, gatfExecutorConfig.getOutFilesDir());
						nresource.mkdirs();
						Assert.assertTrue("Out files directory could not be created...", nresource.exists());
					}
				}
				else
				{
					File resource = new File(System.getProperty("user.dir"));
					File file = new File(resource, gatfExecutorConfig.getOutFilesDir());
					if(flag)
					{
						removeFolder(file);
						File nresource = new File(resource, gatfExecutorConfig.getOutFilesDir());
						nresource.mkdir();
						Assert.assertTrue("Out files directory could not be created...", nresource.exists());
					}
				}
			} catch (Exception e) {
				gatfExecutorConfig.setOutFilesDir(null);
			}
			Assert.assertNotNull("Testcase out file directory not found...", gatfExecutorConfig.getOutFilesDir());
		}
		else
		{
			File resource = new File(System.getProperty("user.dir"));
			if(flag)
			{
				removeFolder(resource);
				File nresource = new File(System.getProperty("user.dir"), "out");
				nresource.mkdir();
			}
			gatfExecutorConfig.setOutFilesDir("out");
			gatfExecutorConfig.setOutFilesBasePath(System.getProperty("user.dir"));
		}
		
		if(flag)
		{
			initSoapContextAndHttpHeaders();
			
			initTestDataProviderAndGlobalVariables();
		}
		
		initServerLogsApis();
	}
	
	public void initServerLogsApis() throws Exception {
		File basePath = new File(gatfExecutorConfig.getTestCasesBasePath());
		File resource = new File(basePath, GATF_SERVER_LOGS_API_FILE_NM);
		if(resource.exists() && gatfExecutorConfig.isFetchFailureLogs()) {
			TestCaseFinder finder = new XMLTestCaseFinder();
			serverLogsApiLst.clear();
			serverLogsApiLst.addAll(finder.resolveTestCases(resource));
			for (TestCase testCase : serverLogsApiLst) {
				testCase.setSourcefileName(GATF_SERVER_LOGS_API_FILE_NM);
				if(testCase.getSimulationNumber()==null)
				{
					testCase.setSimulationNumber(0);
				}
				testCase.setExternalApi(true);
				testCase.validate(getHttpHeaders(), null);
			}
		}
	}

	private void initTestDataProviderAndGlobalVariables() throws Exception {
		GatfTestDataConfig gatfTestDataConfig = null;
		if(gatfExecutorConfig.getTestDataConfigFile()!=null) {
			File file = getResourceFile(gatfExecutorConfig.getTestDataConfigFile());
			Assert.assertNotNull("Testdata configuration file not found...", file);
			Assert.assertEquals("Testdata configuration file not found...", file.exists(), true);
			
			if(gatfExecutorConfig.getTestDataConfigFile().trim().endsWith(".xml")) {
				XStream xstream = new XStream(new DomDriver("UTF-8"));
		       
		        xstream.allowTypes(new Class[]{GatfTestDataConfig.class, GatfTestDataProvider.class});
				xstream.processAnnotations(new Class[]{GatfTestDataConfig.class, GatfTestDataProvider.class});
				xstream.alias("gatf-testdata-provider", GatfTestDataProvider.class);
				xstream.alias("args", String[].class);
				xstream.alias("arg", String.class);
				gatfTestDataConfig = (GatfTestDataConfig)xstream.fromXML(file);
			} else  {
				gatfTestDataConfig = WorkflowContextHandler.OM.readValue(file, GatfTestDataConfig.class);
			}
			gatfExecutorConfig.setGatfTestDataConfig(gatfTestDataConfig);
		} else {
			gatfTestDataConfig = gatfExecutorConfig.getGatfTestDataConfig();
		}
		
		handleTestDataSourcesAndHooks(gatfTestDataConfig);
	}

	public void handleTestDataSourcesAndHooks(GatfTestDataConfig gatfTestDataConfig) {
		if(gatfTestDataConfig!=null) {
			getWorkflowContextHandler().addGlobalVariables(gatfTestDataConfig.getGlobalVariables());
			
			if(gatfTestDataConfig.getDataSourceList()!=null)
			{
				handleDataSources(gatfTestDataConfig.getDataSourceList(), false);
			}
			
			if(gatfTestDataConfig.getDataSourceListForProfiling()!=null)
			{
				handleDataSources(gatfTestDataConfig.getDataSourceListForProfiling(), true);
			}
			
			if(gatfTestDataConfig.getDataSourceHooks()!=null)
			{
				handleHooks(gatfTestDataConfig.getDataSourceHooks());
			}
				
			if(gatfTestDataConfig.getProviderTestDataList()!=null)
			{
				handleProviders(gatfTestDataConfig.getProviderTestDataList());
			}
		}
	}

	public static Map<String, String> getHttpHeadersMap() throws Exception
	{
		Map<String, String> headers = new HashMap<String, String>();
		Field[] declaredFields = HttpHeaders.class.getDeclaredFields();
		for (Field field : declaredFields) {
			if (java.lang.reflect.Modifier.isStatic(field.getModifiers())
					&& field.getType().equals(String.class)) {
				headers.put(field.get(null).toString().toLowerCase(), field.get(null).toString());
			}
		}
		return headers;
	}
	
	private void initSoapContextAndHttpHeaders() throws Exception
	{
		Field[] declaredFields = HttpHeaders.class.getDeclaredFields();
		for (Field field : declaredFields) {
			if (java.lang.reflect.Modifier.isStatic(field.getModifiers())
					&& field.getType().equals(String.class)) {
				httpHeaders.put(field.get(null).toString().toLowerCase(), field.get(null).toString());
			}
		}
		
		File file = null;
		if(gatfExecutorConfig.getWsdlLocFile()!=null && !gatfExecutorConfig.getWsdlLocFile().trim().isEmpty())
			file = getResourceFile(gatfExecutorConfig.getWsdlLocFile());
		
		if(file!=null)
		{
			Scanner s = new Scanner(file);
			s.useDelimiter("\n");
			List<String> list = new ArrayList<String>();
			while (s.hasNext()) {
				list.add(s.next().replace("\r", ""));
			}
			s.close();
	
			for (String wsdlLoc : list) {
				if(!wsdlLoc.trim().isEmpty())
				{
					String[] wsdlLocParts = wsdlLoc.split(",");
					logger.info("Started Parsing WSDL location - " + wsdlLocParts[1]);
					Wsdl wsdl = Wsdl.parse(wsdlLocParts[1]);
					for (QName bindingName : wsdl.getBindings()) {
						SoapBuilder builder = wsdl.getBuilder(bindingName);
						for (SoapOperation operation : builder.getOperations()) {
							String request = builder.buildInputMessage(operation);
							DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
							DocumentBuilder db = dbf.newDocumentBuilder();
							Document soapMessage = db.parse(new ByteArrayInputStream(request.getBytes()));
							
							if(gatfExecutorConfig.isDistributedLoadTests()) {
								soapStrMessages.put(wsdlLocParts[0]+operation.getOperationName(), request);
							}
							
							soapMessages.put(wsdlLocParts[0]+operation.getOperationName(), soapMessage);
							if(operation.getSoapAction()!=null) {
								soapActions.put(wsdlLocParts[0]+operation.getOperationName(), operation.getSoapAction());
							}
							logger.info("Adding message for SOAP operation - " + operation.getOperationName());
						}
						soapEndpoints.put(wsdlLocParts[0], builder.getServiceUrls().get(0));
						logger.info("Adding SOAP Service endpoint - " + builder.getServiceUrls().get(0));
					}
					logger.info("Done Parsing WSDL location - " + wsdlLocParts[1]);
				}
			}
		}
	}

	public void shutdown() {
		for (GatfTestDataSourceHook dataSourceHook : dataSourceHooksMap.values()) {
			TestDataSource dataSource = dataSourceMap.get(dataSourceHook.getDataSourceName());
			
			Assert.assertNotNull("No DataSource found", dataSource);
			
			if(dataSourceHook.isExecuteOnShutdown() && dataSourceHook.getQueryStrs()!=null) {
				for (String query : dataSourceHook.getQueryStrs()) {
					boolean flag = false;
					try {
						flag = dataSource.execute(query);
					} catch (Throwable e) {
					}
					if(!flag) {
						logger.severe("Shutdown DataSourceHook execution for " + dataSourceHook.getHookName()
								+ " failed, queryString = " + query);
					}
				}
			}
		}
		
		for (GatfTestDataSourceHook dataSourceHook : dataSourceHooksMap.values()) {
			TestDataSource dataSource = dataSourceMap.get(dataSourceHook.getDataSourceName());
			
			Assert.assertNotNull("No DataSource found", dataSource);
			
			dataSource.destroy();
		}
	}
	
	public void executeDataSourceHook(String hookName) {
		GatfTestDataSourceHook dataSourceHook = dataSourceHooksMap.get(hookName);
		Assert.assertNotNull("No DataSourceHook found", dataSourceHook);
		
		TestDataSource dataSource = dataSourceMap.get(dataSourceHook.getDataSourceName());
		Assert.assertNotNull("No DataSource found", dataSource);
		
		for (String query : dataSourceHook.getQueryStrs()) {
			boolean flag = dataSource.execute(query);
			if(!flag) {
				Assert.assertNotNull("DataSourceHook execution for " + dataSourceHook.getHookName()
						+ " failed...", null);
			}
		}
	}
	
	@SuppressWarnings("rawtypes")
	private void handleDataSources(List<GatfTestDataSource> dataSourceList, boolean forProfiling)
	{
		for (GatfTestDataSource dataSource : dataSourceList) {
			Assert.assertNotNull("DataSource name is not defined", dataSource.getDataSourceName());
			Assert.assertNotNull("DataSource class is not defined", dataSource.getDataSourceClass());
			Assert.assertNotNull("DataSource args not defined", dataSource.getArgs());
			Assert.assertTrue("DataSource args empty", dataSource.getArgs().length>0);
			Assert.assertNull("Duplicate DataSource name found", dataSourceMap.get(dataSource.getDataSourceName()));
			
			TestDataSource testDataSource = null;
			if(SQLDatabaseTestDataSource.class.getCanonicalName().equals(dataSource.getDataSourceClass())) {
				testDataSource = new SQLDatabaseTestDataSource();
			} else if(MongoDBTestDataSource.class.getCanonicalName().equals(dataSource.getDataSourceClass())) {
				testDataSource = new MongoDBTestDataSource();
			} else {
				try {
					Class claz = loadCustomClass(dataSource.getDataSourceClass());
					Class[] classes = claz.getInterfaces();
					boolean validProvider = false;
					if(classes!=null) {
						for (Class class1 : classes) {
							if(class1.equals(TestDataSource.class)) {
								validProvider = true;
								break;
							}
						}
					}
					Assert.assertTrue("DataSource class should extend the TestDataSource class", validProvider);
					@SuppressWarnings("unchecked")
					Object providerInstance = claz.getDeclaredConstructor().newInstance();
					testDataSource = (TestDataSource)providerInstance;
				} catch (Throwable e) {
					throw new AssertionError(e);
				}
			}
			
			testDataSource.setClassName(dataSource.getDataSourceClass());
			testDataSource.setArgs(dataSource.getArgs());
			testDataSource.setContext(this);
			testDataSource.setDataSourceName(dataSource.getDataSourceName());
			if(dataSource.getPoolSize()>1)
			{
				testDataSource.setPoolSize(dataSource.getPoolSize());
			}
			
			if(forProfiling)
			{
				testDataSource.setPoolSize(1);
				testDataSource.init();
				dataSourceMapForProfiling.put(dataSource.getDataSourceName(), testDataSource);
			}
			else
			{
				testDataSource.init();
				dataSourceMap.put(dataSource.getDataSourceName(), testDataSource);
			}
		}
	}
	
	public Map<String, TestDataSource> getDataSourceMapForProfiling()
	{
		return dataSourceMapForProfiling;
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void handleHooks(List<GatfTestDataSourceHook> dataSourceHooks)
	{
		for (GatfTestDataSourceHook dataSourceHook : dataSourceHooks) {
			Assert.assertNotNull("DataSourceHook name is not defined", dataSourceHook.getHookName());
			Assert.assertNotNull("DataSourceHook query string is not defined", dataSourceHook.getQueryStrs());
			Assert.assertNull("Duplicate DataSourceHook name found", dataSourceHooksMap.get(dataSourceHook.getHookName()));
			
			TestDataSource dataSource = null;
			if(dataSourceHook.getDataSourceName()!=null && dataSourceHook.getHookClass()==null)
			{
				dataSource = dataSourceMap.get(dataSourceHook.getDataSourceName());
				Assert.assertNotNull("No DataSource found", dataSource);
			}
			else if(dataSourceHook.getDataSourceName()!=null && dataSourceHook.getHookClass()!=null)
			{
				Assert.assertNotNull("Specify either hookClass or dataSourceName", null);
			}
			else if(dataSourceHook.getDataSourceName()==null && dataSourceHook.getHookClass()==null)
			{
				Assert.assertNotNull("Specify any one of hookClass or dataSourceName", null);
			}
			
			dataSourceHooksMap.put(dataSourceHook.getHookName(), dataSourceHook);
			
			TestDataHook testDataHook = null;
			if(dataSourceHook.getHookClass()!=null) {
				try {
					Class claz = loadCustomClass(dataSourceHook.getHookClass());
					Class[] classes = claz.getInterfaces();
					boolean validProvider = false;
					if(classes!=null) {
						for (Class class1 : classes) {
							if(class1.equals(TestDataProvider.class)) {
								validProvider = true;
								break;
							}
						}
					}
					Assert.assertTrue("Hook class should implement the TestDataHook class", validProvider);
					Object providerInstance = claz.getDeclaredConstructor().newInstance();
					testDataHook = (TestDataHook)providerInstance;
				} catch (Throwable e) {
					throw new AssertionError(e);
				}
			} else {
				testDataHook = dataSource;
			}
			
			if(dataSourceHook.isExecuteOnStart()) {
				for (String query : dataSourceHook.getQueryStrs()) {
					boolean flag = false;
					try {
						flag = testDataHook.execute(query);
					} catch (Throwable e) {
					}
					if(!flag) {
						logger.severe("Startup DataSourceHook execution for " + dataSourceHook.getHookName()
								+ " failed, queryString = " + query);
					}
				}
			}
		}
	}
	
	private void handleProviders(List<GatfTestDataProvider> providerTestDataList)
	{
		for (GatfTestDataProvider provider : providerTestDataList) {
			Assert.assertNotNull("Provider name is not defined", provider.getProviderName());
			
			Assert.assertNotNull("Provider properties is not defined", provider.getProviderProperties());
			
			Assert.assertNull("Duplicate Provider name found", providerTestDataMap.get(provider.getProviderName()));
			
			TestDataSource dataSource = null;
			if(provider.getDataSourceName()!=null && provider.getProviderClass()==null)
			{	
				Assert.assertNotNull("Provider DataSource name is not defined", provider.getDataSourceName());
				dataSource = dataSourceMap.get(provider.getDataSourceName());
				
				Assert.assertNotNull("No DataSource found", dataSource);
				
				if(dataSource instanceof MongoDBTestDataSource)
				{
					Assert.assertNotNull("Provider query string is not defined", provider.getQueryStr());
					Assert.assertNotNull("Provider source properties not defined", provider.getSourceProperties());
				}
				
				if(dataSource instanceof SQLDatabaseTestDataSource)
				{
					Assert.assertNotNull("Provider query string is not defined", provider.getQueryStr());
				}
			}
			else if(provider.getDataSourceName()!=null && provider.getProviderClass()!=null)
			{
				Assert.assertNotNull("Specify either providerClass or dataSourceName", null);
			}
			else if(provider.getDataSourceName()==null && provider.getProviderClass()==null)
			{
				Assert.assertNotNull("Specify any one of providerClass or dataSourceName", null);
			}
			
			
			if(provider.isEnabled()==null) {
				provider.setEnabled(true);
			}
			
			if(!provider.isEnabled()) {
				logger.info("Provider " + provider.getProviderName() + " is Disabled...");
				continue;
			}
			
			if(provider.isLive()) {
				liveProviders.put(provider.getProviderName(), provider);
				logger.info("Provider " + provider.getProviderName() + " is a Live one...");
				continue;
			}
			
			List<Map<String, String>> testData = getProviderData(provider, null);
			if(gatfExecutorConfig.isSeleniumExecutor() && gatfExecutorConfig.getConcurrentUserSimulationNum()>1) {
			    for (int i = 0; i < gatfExecutorConfig.getConcurrentUserSimulationNum(); i++)
                {
			        if(FileTestDataProvider.class.getCanonicalName().equals(provider.getProviderClass().trim())) {
			            if(i==0) {
			                providerTestDataMap.put(provider.getProviderName()+(i+1), testData);
			                continue;
			            }
			            GatfTestDataProvider tp = new GatfTestDataProvider(provider);
	                    tp.setProviderName(provider.getProviderName()+(i+1));
	                    tp.getArgs()[0] = tp.getArgs()[0] + i;
	                    try {
	                        logger.info("Concurrent simulation scenario #"+(i+1)+" fetching provider with filePath "+tp.getArgs()[0]);
	                        List<Map<String, String>> testDataT = getProviderData(tp, null);
	                        if(testDataT==null) {
	                            testDataT = testData;
	                        }
	                        providerTestDataMap.put(tp.getProviderName(), testDataT);
	                    } catch (Throwable e) {
	                        logger.severe("Cannot find data provider for the concurrent simulation scenario #"+(i+1)+" with name " + tp.getProviderName());
	                        providerTestDataMap.put(tp.getProviderName(), testData);
	                    }
			        } else {
			            logger.severe("Concurrent simulation scenarios need file data providers");
			        }
                }
			} else {
			    providerTestDataMap.put(provider.getProviderName(), testData);
			}
		}
	}
	
	public List<Map<String, String>> getLiveProviderData(String provName, TestCase testCase)
	{
		GatfTestDataProvider provider = liveProviders.get(provName);
		return getProviderData(provider, testCase);
	}
	
	public List<Map<String, String>> getAnyProviderData(String provName, TestCase testCase)
	{
		if(liveProviders.containsKey(provName))
		{
			GatfTestDataProvider provider = liveProviders.get(provName);
			return getProviderData(provider, testCase);
		}
		else
		{
			return providerTestDataMap.get(provName);
		}
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private List<Map<String, String>> getProviderData(GatfTestDataProvider provider, TestCase testCase) {
		
		TestDataSource dataSource = dataSourceMap.get(provider.getDataSourceName());
		
		TestDataProvider testDataProvider = null;
		List<Map<String, String>> testData = null;
		if(provider.getProviderClass()!=null) {
			if(FileTestDataProvider.class.getCanonicalName().equals(provider.getProviderClass().trim())) {
				testDataProvider = new FileTestDataProvider();
			} else if(InlineValueTestDataProvider.class.getCanonicalName().equals(provider.getProviderClass().trim())) {
				testDataProvider = new InlineValueTestDataProvider();
			} else if(RandomValueTestDataProvider.class.getCanonicalName().equals(provider.getProviderClass().trim())) {
				testDataProvider = new RandomValueTestDataProvider();
			} else {
				try {
					Class claz = loadCustomClass(provider.getProviderClass());
					Class[] classes = claz.getInterfaces();
					boolean validProvider = false;
					if(classes!=null) {
						for (Class class1 : classes) {
							if(class1.equals(TestDataProvider.class)) {
								validProvider = true;
								break;
							}
						}
					}
					Assert.assertTrue("Provider class should implement the TestDataProvider class", validProvider);
					Object providerInstance = claz.getDeclaredConstructor().newInstance();
					testDataProvider = (TestDataProvider)providerInstance;
				} catch (Throwable e) {
					throw new AssertionError(e);
				}
			}
		} else {
			testDataProvider = dataSource;
		}
		
		//Live provider queries can have templatized parameter names
		if(provider.isLive() && provider.getQueryStr()!=null)
		{
			String oQs = provider.getQueryStr();
			provider = new GatfTestDataProvider(provider);
			if(testCase!=null)
			{
				provider.setQueryStr(getWorkflowContextHandler().evaluateTemplate(testCase, provider.getQueryStr(), this));
				if(provider.getQueryStr()==null || provider.getQueryStr().isEmpty()) {
					provider.setQueryStr(oQs);
				}
			}
		}
		
		testData = testDataProvider.provide(provider, this);
		if(testDataProvider instanceof FileTestDataProvider) {
			fileProviderStateMap.put(provider.getProviderName(), ((FileTestDataProvider)testDataProvider).getHash());
		}
		return testData;
	}

	public DistributedAcceptanceContext getDistributedContext(String node, List<Object[]> selTestdata)
	{
		DistributedAcceptanceContext distributedTestContext = new DistributedAcceptanceContext();
		distributedTestContext.setConfig(gatfExecutorConfig);
		distributedTestContext.setHttpHeaders(httpHeaders);
		distributedTestContext.setSoapActions(soapActions);
		distributedTestContext.setSoapEndpoints(soapEndpoints);
		distributedTestContext.setSoapMessages(soapStrMessages);
		distributedTestContext.setNode(node);
		distributedTestContext.setSelTestdata(selTestdata);
		
		return distributedTestContext;
	}
	
	@SuppressWarnings("rawtypes")
	private Class loadCustomClass(String className) throws ClassNotFoundException
	{
		return getProjectClassLoader().loadClass(className);
	}
	
	public List<TestCase> getServerLogsApiLst() {
		return serverLogsApiLst;
	}
	
	public TestCase getServerLogApi(boolean isAuth)
	{
		if(serverLogsApiLst.size()>0)
		{
			for (TestCase tc : serverLogsApiLst) {
				if(isAuth && gatfExecutorConfig.isServerLogsApiAuthEnabled() && "authapi".equals(tc.getName()))
				{
					tc.setServerApiAuth(true);
					tc.setExternalApi(true);
					return tc;
				}
				else if(!isAuth && "targetapi".equals(tc.getName()))
				{
					tc.setServerApiTarget(true);
					tc.setSecure(gatfExecutorConfig.isServerLogsApiAuthEnabled());
					tc.setExternalApi(true);
					return tc;
				}
			}
		}
		return null;
	}
}
 @XStreamAlias("gatf-execute-config")
@JsonAutoDetect(getterVisibility=Visibility.NONE, fieldVisibility=Visibility.ANY, isGetterVisibility=Visibility.NONE)
@JsonInclude(value = Include.NON_NULL)
public class GatfExecutorConfig implements Serializable, GatfPluginConfig {

	private static final long serialVersionUID = 1L;
	
	private String baseUrl;
	
	private String testCasesBasePath;
	
	private String testCaseDir;
	
	private String outFilesBasePath;
	
	private String outFilesDir;
	
	private boolean authEnabled;
	
	private String authUrl;
	
	private String authExtractAuth;
	
	private String authParamsDetails;
	
	private String wsdlLocFile;
	
	private boolean soapAuthEnabled;
	
	private String soapAuthWsdlKey;
	
	private String soapAuthOperation;
	
	private String soapAuthExtractAuth;
	
	private Integer numConcurrentExecutions;
	
	private boolean httpCompressionEnabled;
	
	private Integer httpConnectionTimeout;
	
	private Integer httpRequestTimeout;
	
	private Integer concurrentUserSimulationNum;
	
	private String testDataConfigFile;
	
	private String authDataProvider;
	
	private boolean compareEnabled;
	
	private GatfTestDataConfig gatfTestDataConfig; 
	
	private Boolean enabled;
	
	private String[] testCaseHooksPaths;
	
	private boolean loadTestingEnabled;
	
	private Long loadTestingTime = 0L;
	
	private boolean distributedLoadTests;
	
	private String[] distributedNodes;
	
	@XStreamOmitField
	private Integer compareBaseUrlsNum;
	
	private Long concurrentUserRampUpTime;
	
	private Integer loadTestingReportSamples;
	
	private boolean debugEnabled;
	
	private String[] ignoreFiles;
	
	private String[] orderedFiles;
	
	private boolean isOrderByFileName;
	
	private boolean isServerLogsApiAuthEnabled;
	
	private String serverLogsApiAuthExtractAuth;
	
	private boolean isFetchFailureLogs;
	
	private Integer repeatSuiteExecutionNum = 0;
	
	private boolean isGenerateExecutionLogs = false;
	
	private boolean isSeleniumExecutor = false;
	
	private boolean isSeleniumModuleTests = false;
	
	private String[] seleniumScripts;
	
	private SeleniumDriverConfig[] seleniumDriverConfigs;
	
	private String seleniumLoggerPreferences;
	
    private String javaHome;
    
    private String javaVersion;
    
    private String gatfJarPath;
    
    private boolean selDebugger;
    
    private String wrkPath;
    
    private String wrk2Path;
    
    private String vegetaPath;
    
    private String autocannonPath;
	
	public String getBaseUrl() {
		return baseUrl;
	}

	public void setBaseUrl(String baseUrl) {
		this.baseUrl = baseUrl;
	}

	public String getTestCasesBasePath() {
		return testCasesBasePath;
	}

	public void setTestCasesBasePath(String testCasesBasePath) {
		this.testCasesBasePath = testCasesBasePath;
	}

	public String getTestCaseDir() {
		return testCaseDir;
	}

	public void setTestCaseDir(String testCaseDir) {
		this.testCaseDir = testCaseDir;
	}

	public String getOutFilesBasePath() {
		return outFilesBasePath;
	}

	public void setOutFilesBasePath(String outFilesBasePath) {
		this.outFilesBasePath = outFilesBasePath;
	}

	public String getOutFilesDir() {
		return outFilesDir;
	}

	public void setOutFilesDir(String outFilesDir) {
		this.outFilesDir = outFilesDir;
	}

	public void setAuthEnabled(boolean authEnabled) {
		this.authEnabled = authEnabled;
	}

	public String getAuthUrl() {
		return authUrl;
	}

	public void setAuthUrl(String authUrl) {
		this.authUrl = authUrl;
	}

	public String getAuthExtractAuth() {
		return authExtractAuth;
	}

	public void setAuthExtractAuth(String authExtractAuth) {
		this.authExtractAuth = authExtractAuth;
	}

	public String getWsdlLocFile() {
		return wsdlLocFile;
	}

	public void setWsdlLocFile(String wsdlLocFile) {
		this.wsdlLocFile = wsdlLocFile;
	}

	public void setSoapAuthEnabled(boolean soapAuthEnabled) {
		this.soapAuthEnabled = soapAuthEnabled;
	}

	public String getSoapAuthWsdlKey() {
		return soapAuthWsdlKey;
	}

	public void setSoapAuthWsdlKey(String soapAuthWsdlKey) {
		this.soapAuthWsdlKey = soapAuthWsdlKey;
	}

	public String getSoapAuthOperation() {
		return soapAuthOperation;
	}

	public void setSoapAuthOperation(String soapAuthOperation) {
		this.soapAuthOperation = soapAuthOperation;
	}

	public String getSoapAuthExtractAuth() {
		return soapAuthExtractAuth;
	}

	public void setSoapAuthExtractAuth(String soapAuthExtractAuth) {
		this.soapAuthExtractAuth = soapAuthExtractAuth;
	}

	public Integer getNumConcurrentExecutions() {
		return numConcurrentExecutions;
	}

	public void setNumConcurrentExecutions(Integer numConcurrentExecutions) {
		this.numConcurrentExecutions = numConcurrentExecutions;
	}

	public String[] getAuthExtractAuthParams() {
		if(authExtractAuth!=null) {
			return authExtractAuth.split(",");
		}
		return null;
	}
	
	public String[] getServerApiAuthExtractAuthParams() {
		if(serverLogsApiAuthExtractAuth!=null) {
			return serverLogsApiAuthExtractAuth.split(",");
		}
		return null;
	}
	
	public String[] getAuthParamDetails() {
		if(authParamsDetails!=null) {
			return authParamsDetails.split(",");
		}
		return null;
	}
	
	public String[] getSoapAuthExtractAuthParams() {
		if(soapAuthExtractAuth!=null) {
			return soapAuthExtractAuth.split(",");
		}
		return null;
	}
	
	public Boolean isEnabled() {
		return enabled;
	}

	public void setEnabled(Boolean enabled) {
		this.enabled = enabled;
	}

	public boolean isAuthEnabled() {
		return authEnabled && getAuthExtractAuthParams()!=null;
	}
	
	public boolean isSoapAuthEnabled() {
		return soapAuthEnabled && getSoapAuthExtractAuthParams()!=null;
	}
	
	public boolean isSoapAuthTestCase(TestCase tcase) {
		return getSoapAuthWsdlKey()!=null && getSoapAuthOperation()!=null &&
				(getSoapAuthWsdlKey() + 
						getSoapAuthOperation()).equals(tcase.getWsdlKey()+tcase.getOperationName());
	}

	public boolean isHttpCompressionEnabled() {
		return httpCompressionEnabled;
	}

	public void setHttpCompressionEnabled(boolean httpCompressionEnabled) {
		this.httpCompressionEnabled = httpCompressionEnabled;
	}

	public Integer getHttpConnectionTimeout() {
		return httpConnectionTimeout;
	}

	public void setHttpConnectionTimeout(Integer httpConnectionTimeout) {
		this.httpConnectionTimeout = httpConnectionTimeout;
	}

	public Integer getHttpRequestTimeout() {
		return httpRequestTimeout;
	}

	public void setHttpRequestTimeout(Integer httpRequestTimeout) {
		this.httpRequestTimeout = httpRequestTimeout;
	}
	
	public Integer getConcurrentUserSimulationNum() {
		return concurrentUserSimulationNum;
	}

	public void setConcurrentUserSimulationNum(Integer concurrentUserSimulationNum) {
		this.concurrentUserSimulationNum = concurrentUserSimulationNum;
	}
	
	public GatfTestDataConfig getGatfTestDataConfig() {
		return gatfTestDataConfig;
	}

	public void setGatfTestDataConfig(GatfTestDataConfig gatfTestDataConfig) {
		this.gatfTestDataConfig = gatfTestDataConfig;
	}

	public String getTestDataConfigFile() {
		return testDataConfigFile;
	}

	public void setTestDataConfigFile(String testDataConfigFile) {
		this.testDataConfigFile = testDataConfigFile;
	}

	public String getAuthDataProvider() {
		return authDataProvider;
	}

	public void setAuthDataProvider(String authDataProvider) {
		this.authDataProvider = authDataProvider;
	}

	public Integer getCompareBaseUrlsNum() {
		return compareBaseUrlsNum;
	}

	public void setCompareBaseUrlsNum(Integer compareBaseUrlsNum) {
		this.compareBaseUrlsNum = compareBaseUrlsNum;
	}

	public boolean isCompareEnabled() {
		return compareEnabled;
	}

	public void setCompareEnabled(boolean compareEnabled) {
		this.compareEnabled = compareEnabled;
	}

	public String getAuthParamsDetails() {
		return authParamsDetails;
	}

	public void setAuthParamsDetails(String authParamsDetails) {
		this.authParamsDetails = authParamsDetails;
	}

	public String[] getTestCaseHooksPaths() {
		return testCaseHooksPaths;
	}

	public void setTestCaseHooksPaths(String[] testCaseHooksPaths) {
		this.testCaseHooksPaths = testCaseHooksPaths;
	}

	public boolean isLoadTestingEnabled() {
		return loadTestingEnabled;
	}

	public void setLoadTestingEnabled(boolean loadTestingEnabled) {
		this.loadTestingEnabled = loadTestingEnabled;
	}

	public boolean isFetchFailureLogs() {
		return isFetchFailureLogs;
	}

	public void setFetchFailureLogs(boolean isFetchFailureLogs) {
		this.isFetchFailureLogs = isFetchFailureLogs;
	}

	public Long getLoadTestingTime() {
		return loadTestingTime;
	}

	public void setLoadTestingTime(Long loadTestingTime) {
		this.loadTestingTime = loadTestingTime;
	}

	public boolean isDistributedLoadTests() {
		return distributedLoadTests;
	}

	public void setDistributedLoadTests(boolean distributedLoadTests) {
		this.distributedLoadTests = distributedLoadTests;
	}

	public String[] getDistributedNodes() {
		return distributedNodes;
	}

	public void setDistributedNodes(String[] distributedNodes) {
		this.distributedNodes = distributedNodes;
	}

	public Long getConcurrentUserRampUpTime() {
		return concurrentUserRampUpTime;
	}

	public void setConcurrentUserRampUpTime(Long concurrentUserRampUpTime) {
		this.concurrentUserRampUpTime = concurrentUserRampUpTime;
	}

	public Integer getLoadTestingReportSamples() {
		return loadTestingReportSamples;
	}

	public void setLoadTestingReportSamples(Integer loadTestingReportSamples) {
		this.loadTestingReportSamples = loadTestingReportSamples;
	}

	public boolean isDebugEnabled() {
		return debugEnabled;
	}

	public void setDebugEnabled(boolean debugEnabled) {
		this.debugEnabled = debugEnabled;
	}

	public String[] getIgnoreFiles() {
		return ignoreFiles;
	}

	public void setIgnoreFiles(String[] ignoreFiles) {
		this.ignoreFiles = ignoreFiles;
	}

	public String[] getOrderedFiles() {
		return orderedFiles;
	}

	public void setOrderedFiles(String[] orderedFiles) {
		this.orderedFiles = orderedFiles;
	}

	public boolean isOrderByFileName() {
		return isOrderByFileName;
	}

	public void setOrderByFileName(boolean isOrderByFileName) {
		this.isOrderByFileName = isOrderByFileName;
	}

	public boolean isServerLogsApiAuthEnabled() {
		return isServerLogsApiAuthEnabled;
	}

	public void setServerLogsApiAuthEnabled(boolean isServerLogsApiAuthEnabled) {
		this.isServerLogsApiAuthEnabled = isServerLogsApiAuthEnabled;
	}

	public String getServerLogsApiAuthExtractAuth() {
		return serverLogsApiAuthExtractAuth;
	}

	public void setServerLogsApiAuthExtractAuth(String serverLogsApiAuthExtractAuth) {
		this.serverLogsApiAuthExtractAuth = serverLogsApiAuthExtractAuth;
	}

	public Integer getRepeatSuiteExecutionNum() {
		return repeatSuiteExecutionNum;
	}

	public void setRepeatSuiteExecutionNum(Integer repeatSuiteExecutionNum) {
		this.repeatSuiteExecutionNum = repeatSuiteExecutionNum;
	}

	public boolean isGenerateExecutionLogs() {
		return isGenerateExecutionLogs;
	}

	public void setGenerateExecutionLogs(boolean isGenerateExecutionLogs) {
		this.isGenerateExecutionLogs = isGenerateExecutionLogs;
	}

	public boolean isSeleniumExecutor() {
		return isSeleniumExecutor;
	}

	public void setSeleniumExecutor(boolean isSeleniumExecutor) {
		this.isSeleniumExecutor = isSeleniumExecutor;
	}

	public boolean isSeleniumModuleTests() {
		return isSeleniumModuleTests;
	}

	public void setSeleniumModuleTests(boolean isSeleniumModuleTests) {
		this.isSeleniumModuleTests = isSeleniumModuleTests;
	}

	public String[] getSeleniumScripts() {
		return seleniumScripts;
	}

	public void setSeleniumScripts(String[] seleniumScripts) {
		this.seleniumScripts = seleniumScripts;
	}

	public SeleniumDriverConfig[] getSeleniumDriverConfigs() {
		return seleniumDriverConfigs;
	}

	public void setSeleniumDriverConfigs(SeleniumDriverConfig[] seleniumDriverConfigs) {
		this.seleniumDriverConfigs = seleniumDriverConfigs;
	}
	
	public Map<String, SeleniumDriverConfig> getSelDriverConfigMap() {
	    Map<String, SeleniumDriverConfig> mp = new HashMap<String, SeleniumDriverConfig>();
	    for (SeleniumDriverConfig sc : seleniumDriverConfigs)
        {
            if(!mp.containsKey(sc.getDriverName()) && sc.getName().matches("chrome|firefox|ie|opera|edge|safari|appium-android|appium-ios|selendroid|ios-driver"))
            {
                mp.put(sc.getName(), sc);
            }
        }
	    return mp;
	}
	
	public String getSeleniumLoggerPreferences()
    {
        return seleniumLoggerPreferences;
    }

    public void setSeleniumLoggerPreferences(String seleniumLoggerPreferences)
    {
        this.seleniumLoggerPreferences = seleniumLoggerPreferences;
    }

    public boolean isValidSeleniumRequest() {
		return isSeleniumExecutor && /*seleniumScripts!=null && seleniumScripts.length>0 && */
		        seleniumDriverConfigs!=null && seleniumDriverConfigs.length>0 &&
		        StringUtils.isNotEmpty(seleniumDriverConfigs[0].getName()) && StringUtils.isNotEmpty(seleniumDriverConfigs[0].getPath());
	}

	public String getJavaHome()
    {
        return javaHome;
    }

    public void setJavaHome(String javaHome)
    {
        this.javaHome = javaHome;
    }

    public String getJavaVersion() {
        return javaVersion;
    }

    public void setJavaVersion(String javaVersion) {
        this.javaVersion = javaVersion;
    }

    public String getGatfJarPath() {
        return gatfJarPath;
    }

    public void setGatfJarPath(String gatfJarPath) {
        this.gatfJarPath = gatfJarPath;
    }

    public boolean isSelDebugger() {
		return selDebugger;
	}

	public void setSelDebugger(boolean selDebugger) {
		this.selDebugger = selDebugger;
	}

	public String getWrkPath() {
		return wrkPath;
	}

	public void setWrkPath(String wrkPath) {
		this.wrkPath = wrkPath;
	}

	public String getWrk2Path() {
		return wrk2Path;
	}

	public void setWrk2Path(String wrk2Path) {
		this.wrk2Path = wrk2Path;
	}

	public String getVegetaPath() {
		return vegetaPath;
	}

	public void setVegetaPath(String vegetaPath) {
		this.vegetaPath = vegetaPath;
	}

	public String getAutocannonPath() {
		return autocannonPath;
	}

	public void setAutocannonPath(String autocannonPath) {
		this.autocannonPath = autocannonPath;
	}

	public void validate()
	{
		Assert.assertTrue("Testcase directory name is blank...", 
				getTestCaseDir()!=null && !getTestCaseDir().trim().isEmpty());
		
		if(isAuthEnabled()) {
			Assert.assertTrue("Invalid auth extract params", getAuthExtractAuthParams().length==4);
			Assert.assertTrue("Invalid auth extract token name", !getAuthExtractAuthParams()[0].isEmpty());
			Assert.assertTrue("Invalid auth extract mode specified, should be one of (xml,json,header,plain,cookie)", 
					getAuthExtractAuthParams()[1].equalsIgnoreCase("json") ||
					getAuthExtractAuthParams()[1].equalsIgnoreCase("xml") ||
					getAuthExtractAuthParams()[1].equalsIgnoreCase("header") ||
					getAuthExtractAuthParams()[1].equalsIgnoreCase("plain") ||
					getAuthExtractAuthParams()[1].equalsIgnoreCase("cookie"));
			Assert.assertTrue("Invalid auth name specified", !getAuthExtractAuthParams()[2].isEmpty());
			Assert.assertTrue("Invalid auth mode specified, should be one of (queryparam,header,cookie)", 
					getAuthExtractAuthParams()[3].equalsIgnoreCase("queryparam") ||
					getAuthExtractAuthParams()[3].equalsIgnoreCase("cookie") ||
					getAuthExtractAuthParams()[3].equalsIgnoreCase("header"));
			Assert.assertTrue("Invalid auth url", getAuthUrl()!=null && !getAuthUrl().isEmpty());
			
			Assert.assertNotNull("Invalid auth param details",getAuthParamsDetails());
			Assert.assertTrue("Invalid auth param details", getAuthParamDetails().length==4);
			Assert.assertTrue("Invalid auth user param name", !getAuthParamDetails()[0].isEmpty());
			Assert.assertTrue("Invalid auth user param name mode specified, should be one of (header,postparam,queryparam)", 
					getAuthParamDetails()[1].equalsIgnoreCase("header") ||
					getAuthParamDetails()[1].equalsIgnoreCase("postparam") ||
					getAuthParamDetails()[1].equalsIgnoreCase("queryparam"));
			Assert.assertTrue("Invalid auth password param name", !getAuthParamDetails()[2].isEmpty());
			Assert.assertTrue("Invalid auth password param name mode specified, should be one of (header,queryparam,header)", 
					getAuthParamDetails()[3].equalsIgnoreCase("queryparam") ||
					getAuthParamDetails()[3].equalsIgnoreCase("postparam") ||
					getAuthParamDetails()[3].equalsIgnoreCase("header"));
			
		}
		
		if(isSoapAuthEnabled()) {
			Assert.assertTrue("Invalid auth soap wsdl key", getSoapAuthWsdlKey()!=null && !getSoapAuthWsdlKey().isEmpty());
			Assert.assertTrue("Invalid auth soap wsdl operation", getSoapAuthOperation()!=null && !getSoapAuthOperation().isEmpty());
			
			Assert.assertTrue("Invalid auth soap extract params", getSoapAuthExtractAuthParams().length==3);
			Assert.assertTrue("Invalid auth soap extract token name", !getSoapAuthExtractAuthParams()[0].isEmpty());
			Assert.assertTrue("Invalid auth soap name specified", !getSoapAuthExtractAuthParams()[1].isEmpty());
			Assert.assertTrue("Invalid auth soap name", !getSoapAuthExtractAuthParams()[2].isEmpty());
			Assert.assertTrue("Invalid auth soap name", getSoapAuthExtractAuthParams()[2].equalsIgnoreCase("queryparam"));
		}
	}
}
 public class WorkflowContextHandler {
	
	public static final ObjectMapper OM = new ObjectMapper();

	private final VelocityEngine engine = new VelocityEngine();
	
	public enum ResponseType {
		JSON,
		XML,
		SOAP,
		PLAIN,
		NONE
	}
	
	public VelocityEngine getEngine() {
		return engine;
	}

	public void init() {
		try {
			engine.init();
		} catch (Exception e) {
		}
	}
	
	private final Map<String, String> globalworkflowContext = new ConcurrentHashMap<String, String>();
	
	private final Map<Integer, Map<String, String>> suiteWorkflowContext = new ConcurrentHashMap<Integer, Map<String, String>>();
	
	private final Map<Integer, Map<String, List<Map<String, String>>>> suiteWorkflowScenarioContext = 
			new ConcurrentHashMap<Integer, Map<String, List<Map<String, String>>>>();
	
	private final Map<Integer, Map<String, String>> cookies = new ConcurrentHashMap<Integer, Map<String, String>>();
	
	public void initializeSuiteContext(int numberOfRuns) {
		suiteWorkflowContext.clear();
		suiteWorkflowScenarioContext.clear();
		cookies.clear();
		
		for (int i = -2; i < numberOfRuns+1; i++) {
			suiteWorkflowContext.put(i, new ConcurrentHashMap<String, String>());
			suiteWorkflowScenarioContext.put(i, new ConcurrentHashMap<String, List<Map<String, String>>>());
			cookies.put(i, new ConcurrentHashMap<String, String>());
		}
	}
	
	public void initializeSuiteContextWithnum(int index) {
		suiteWorkflowContext.put(index, new ConcurrentHashMap<String, String>());
		suiteWorkflowScenarioContext.put(index, new ConcurrentHashMap<String, List<Map<String, String>>>());
		cookies.put(index, new ConcurrentHashMap<String, String>());
	}
	
	void addGlobalVariables(Map<String, String> variableMap) {
		if(variableMap!=null) {
			for (String property : variableMap.keySet()) {
				String value = variableMap.get(property);
				if(value.equals("env.var")) {
					try {
						value = System.getenv(property);
					} catch (Exception e) {
					}
				} else if(value.equals("property.var")) {
					try {
						value = System.getProperty(property);
					} catch (Exception e) {
					}
				} else if(value.startsWith("env.")) {
					try {
						value = System.getenv(value.substring(4));
					} catch (Exception e) {
					}
				} else if(value.startsWith("property.")) {
					try {
						value = System.getProperty(value.substring(9));
					} catch (Exception e) {
					}
				}
				if(value==null) {
					value = variableMap.get(property);
				}
				globalworkflowContext.put(property, value);
			}
		}
	}
	
	public Map<String, String> getSuiteWorkflowContext(TestCase testCase) {
		if(testCase.isServerApiAuth() || testCase.isServerApiTarget()) {
			return suiteWorkflowContext.get(-1);
		} else if(testCase.isExternalApi()) {
			return suiteWorkflowContext.get(-2);
		} else if(testCase.getSimulationNumber()==null) {
			return suiteWorkflowContext.get(0);
		} else {
			return suiteWorkflowContext.get(testCase.getSimulationNumber());
		}
	}
	
	public Map<String, List<Map<String, String>>> getSuiteWorkflowScnearioContext(TestCase testCase) {
		if(testCase.isServerApiAuth() || testCase.isServerApiTarget()) {
			return suiteWorkflowScenarioContext.get(-1);
		} else if(testCase.isExternalApi()) {
			return suiteWorkflowScenarioContext.get(-2);
		} else if(testCase.getSimulationNumber()==null) {
			return suiteWorkflowScenarioContext.get(0);
		} else {
			return suiteWorkflowScenarioContext.get(testCase.getSimulationNumber());
		}
	}
	
	public List<Map<String, String>> getSuiteWorkflowScenarioContextValues(TestCase testCase, String varName) {
		if(testCase.isServerApiAuth() || testCase.isServerApiTarget()) {
			return suiteWorkflowScenarioContext.get(-1).get(varName);
		} else if(testCase.isExternalApi()) {
			return suiteWorkflowScenarioContext.get(-2).get(varName);
		} else if(testCase.getSimulationNumber()==null) {
			return suiteWorkflowScenarioContext.get(0).get(varName);
		} else {
			return suiteWorkflowScenarioContext.get(testCase.getSimulationNumber()).get(varName);
		}
	}
	
	public String getCookie(TestCase testCase, String varName) {
		if(testCase.isServerApiAuth() || testCase.isServerApiTarget()) {
			return cookies.get(-1).get(varName);
		} else if(testCase.isExternalApi()) {
			return cookies.get(-2).get(varName);
		} else if(testCase.getSimulationNumber()==null) {
			return cookies.get(0).get(varName);
		} else {
			return cookies.get(testCase.getSimulationNumber()).get(varName);
		}
	}
	
	public Map<String, String> getCookies(TestCase testCase) {
		if(testCase.isServerApiAuth() || testCase.isServerApiTarget()) {
			return cookies.get(-1);
		} else if(testCase.isExternalApi()) {
			return cookies.get(-2);
		} else if(testCase.getSimulationNumber()==null) {
			return cookies.get(0);
		} else {
			return cookies.get(testCase.getSimulationNumber());
		}
	}
	
	public List<Cookie> storeCookies(TestCase testCase, List<String> cookieLst) {
		int simNumber = testCase.getSimulationNumber()==null?0:testCase.getSimulationNumber();
		if(testCase.isServerApiAuth() || testCase.isServerApiTarget()) {
			simNumber = -1;
		} else if(testCase.isExternalApi()) {
			simNumber = -2;
		} else if(testCase.getSimulationNumber()==null) {
			simNumber = 0;
		}
		List<Cookie> cooklst = new ArrayList<Cookie>();
		if(cookieLst!=null && cookies.get(simNumber)!=null)
		{
			for (String cookie : cookieLst) {
				Cookie c = Cookie.parse(HttpUrl.parse(testCase.getBaseUrl()), cookie);
				cooklst.add(c);
				cookies.get(simNumber).put(c.name(), c.value());
			}
		}
		return cooklst;
	}
	
	public Map<String, String> getGlobalSuiteAndTestLevelParameters(TestCase testCase, Map<String, String> variableMap, int index) {
	    Map<String, String> nmap = new HashMap<String, String>(globalworkflowContext);
	    if(testCase!=null) {
	        index = testCase.getSimulationNumber();
	        if(testCase.isServerApiAuth() || testCase.isServerApiTarget()) {
	            index = -1;
	        } else if(testCase.isExternalApi()) {
	            index = -2;
	        } else if(testCase.getSimulationNumber()==null) {
	            index = 0;
	        }
	        nmap.putAll(suiteWorkflowContext.get(index));
	        if(variableMap!=null && !variableMap.isEmpty()) {
	            nmap.putAll(variableMap);
	        }
	        if(testCase.getCarriedOverVariables()!=null && !testCase.getCarriedOverVariables().isEmpty()) {
	            nmap.putAll(testCase.getCarriedOverVariables());
	        }
	    } else {
	        nmap.putAll(suiteWorkflowContext.get(index));
	        if(variableMap!=null && !variableMap.isEmpty()) {
                nmap.putAll(variableMap);
            }
	    }
		return nmap;
	}
	
	public void addSuiteLevelParameter(int index, String name, String value) {
	    if(suiteWorkflowContext.containsKey(index) && value!=null) {
	        suiteWorkflowContext.get(index).put(name, value);
	    }
	}
	
	public String evaluateTemplate(TestCase testCase, String template, AcceptanceTestContext acontext) {
		StringWriter writer = new StringWriter();
		try {
			Map<String, String> nmap = getGlobalSuiteAndTestLevelParameters(testCase, null, -3);
			if(testCase!=null && !nmap.isEmpty()) {
				if(template!=null) {
					VelocityContext context = new VelocityContext(new HashMap<String, Object>(nmap));
					DataProviderAccessor dpa = new DataProviderAccessor(acontext, testCase);
					context.put("_DPA_", dpa);
					engine.evaluate(context, writer, "ERROR", template);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return writer.toString();
	}
	
	public String templatize(Map<String, Object> variableMap, String template) throws Exception {
	    VelocityContext context = new VelocityContext(variableMap);
	    StringWriter writer = new StringWriter();
        engine.evaluate(context, writer, "ERROR", template);
        return writer.toString();
	}
    
    public String templatize(String template) throws Exception {
        VelocityContext context = new VelocityContext(Collections.<String, Object>unmodifiableMap(globalworkflowContext));
        StringWriter writer = new StringWriter();
        engine.evaluate(context, writer, "ERROR", template);
        return writer.toString();
    }
	
	public void handleContextVariables(TestCase testCase, Map<String, String> variableMap, AcceptanceTestContext acontext) 
			throws Exception {
		
		Map<String, String> nmap = getGlobalSuiteAndTestLevelParameters(testCase, variableMap, -3);
		
		VelocityContext context = new VelocityContext(new HashMap<String, Object>(nmap));
		DataProviderAccessor dpa = new DataProviderAccessor(acontext, testCase);
		context.put("_DPA_", dpa);
		
		//initialize cookies and headers
		if(testCase != null) {
			Map<String, String> cookieMap = getCookies(testCase);
			if(cookieMap!=null) {
				for (Map.Entry<String, String> entry : cookieMap.entrySet()) {
					if(testCase.getHeaders()==null)
					{
						testCase.setHeaders(new HashMap<String, String>());
					}
					testCase.getHeaders().put("Cookie", entry.getKey() + "=" + entry.getValue());
				}
			}
			if(MapUtils.isNotEmpty(testCase.getHeaders())) {
			    for (Map.Entry<String, String> entry : testCase.getHeaders().entrySet()) {
			        StringWriter writer = new StringWriter();
			        engine.evaluate(context, writer, "ERROR", entry.getValue());
			        testCase.getHeaders().put(entry.getKey(), writer.toString());
			    }
			}
		}
		
		if(testCase!=null && !nmap.isEmpty()) {
			if(testCase.getUrl()!=null) {
				StringWriter writer = new StringWriter();
				engine.evaluate(context, writer, "ERROR", testCase.getUrl());
				testCase.setAurl(writer.toString());
			}
			if(testCase.getContent()!=null) {
				StringWriter writer = new StringWriter();
				engine.evaluate(context, writer, "ERROR", testCase.getContent());
				testCase.setAcontent(writer.toString());
			}
			if(testCase.getExQueryPart()!=null) {
				StringWriter writer = new StringWriter();
				engine.evaluate(context, writer, "ERROR", testCase.getExQueryPart());
				testCase.setAexQueryPart(writer.toString());
			}
			if(testCase.getExpectedNodes()!=null && !testCase.getExpectedNodes().isEmpty()) {
				List<String> expectedNodes = new ArrayList<String>();
				for (String nodecase : testCase.getExpectedNodes()) {
					StringWriter writer = new StringWriter();
					engine.evaluate(context, writer, "ERROR", nodecase);
					expectedNodes.add(writer.toString());
				}
				testCase.setAexpectedNodes(expectedNodes);
			}
		} else if(testCase!=null) {
			testCase.setAurl(testCase.getUrl());
			testCase.setAcontent(testCase.getContent());
			testCase.setAexQueryPart(testCase.getExQueryPart());
			testCase.setAexpectedNodes(testCase.getExpectedNodes());
		}
	}
	
	public boolean velocityValidate(TestCase testCase, String template, Map<String, String> smap, 
			AcceptanceTestContext acontext) {
		if(testCase!=null && template!=null) {
			Map<String, String> nmap = getGlobalSuiteAndTestLevelParameters(testCase, null, -3);
			if(smap!=null) {
				nmap.putAll(smap);
			}
			StringWriter writer = new StringWriter();
			String condition = "#if(" +  template + ")true#end";
			try {
				VelocityContext context = new VelocityContext(new HashMap<String, Object>(nmap));
				DataProviderAccessor dpa = new DataProviderAccessor(acontext, testCase);
				context.put("_DPA_", dpa);
				engine.evaluate(context, writer, "ERROR", condition);
			} catch (Exception e) {
				e.printStackTrace();
			}
			return "true".equals(writer.toString());
		}
		return true;
	}
	
	public static List<Map<String, String>> getNodeCountMapList(String xmlValue, String nodeName)
	{
		int responseCount = -1;
		try {
			responseCount = Integer.valueOf(xmlValue);
		} catch (Exception e) {
			throw new AssertionError("Invalid responseMappedCount variable defined, " +
					"derived value should be number - "+nodeName);
		}
		
		List<Map<String, String>> xmlValues = new ArrayList<Map<String,String>>();
		for (int i = 0; i < responseCount; i++) {
			Map<String, String> row = new HashMap<String, String>();
			row.put("index", (i+1)+"");
			xmlValues.add(row);
		}
		
		return xmlValues;
	}
	
	public static List<Map<String, String>> getNodeValueMapList(String propNames, NodeList xmlNodeList)
	{
		List<Map<String, String>> nodeValues = new ArrayList<Map<String,String>>();
		if(propNames.endsWith("*")) 
		{
			for (int i = 0; i < xmlNodeList.getLength(); i++) {
				Map<String, String> row = new HashMap<String, String>();
				
				Node node = xmlNodeList.item(i);
				if(node.getAttributes()!=null && node.getAttributes().getLength()>0)
				{
					for (int j = 0; j < node.getAttributes().getLength(); j++) {
						Attr attr = (Attr) node.getAttributes().item(j);
						row.put(attr.getName(), attr.getValue());
					}
				}
				
				if(node.getChildNodes()!=null && node.getChildNodes().getLength()>0)
				{
					for (int j = 0; j < node.getChildNodes().getLength(); j++) {
						String xmlValue = XMLResponseValidator.getXMLNodeValue(node.getChildNodes().item(j));
						if(xmlValue!=null)
							row.put(node.getChildNodes().item(j).getNodeName(), xmlValue);
					}
				}
				
				String xmlValue = XMLResponseValidator.getXMLNodeValue(node);
				if(xmlValue!=null)
					row.put("this", xmlValue);
				
				if(row.size()>0)
					nodeValues.add(row);
			}
		} 
		else
		{
			String[] props = propNames.split(",");
			
			for (int i = 0; i < xmlNodeList.getLength(); i++) {
				Map<String, String> row = new HashMap<String, String>();
				
				Node node = xmlNodeList.item(i);
				
				boolean found = false;
				
				if(node.getAttributes()!=null && node.getAttributes().getLength()>0)
				{
					for (int j = 0; j < node.getAttributes().getLength(); j++) {
						Attr attr = (Attr) node.getAttributes().item(j);
						for (String propName : props) {
							if(attr.getName().equals(propName)) {
								found = true;
								row.put(propName, attr.getValue());
								break;
							}
						}
					}
				}
				
				if(!found && node.getChildNodes()!=null && node.getChildNodes().getLength()>0)
				{
					for (int j = 0; j < node.getChildNodes().getLength(); j++) {
						for (String propName : props) {
							if(node.getChildNodes().item(j).getNodeName().equals(propName)) {
								found = true;
								String xmlValue = XMLResponseValidator.getXMLNodeValue(node.getChildNodes().item(j));
								row.put(propName, xmlValue);
								break;
							}
						}
					}
				}
				if(row.size()>0)
					nodeValues.add(row);
			}
		}
		return nodeValues;
	}
	
	public static void copyResourcesToDirectory(String resPath, String directory) {
		if(new File(directory).exists()) {
			try {
				/*if(persistHtmlFiles) {
					File tmpfolder = new File(FileUtils.getTempDirectory(), "out");
					if(tmpfolder.exists()) {
						FileUtils.deleteDirectory(tmpfolder);
					}
					tmpfolder.mkdir();
					File[] existingFiles = new File(directory).listFiles(new FilenameFilter() {
						public boolean accept(File folder, String name) {
							return name.endsWith(".html");
						}
					});
					for (File file : existingFiles) {
						FileUtils.moveFile(file, new File(tmpfolder, file.getName()));
					}
				}*/
				FileUtils.deleteDirectory(new File(directory));
			} catch (IOException e) {
			}
		}
		Optional<JarFile> jarFile = ResourceCopy.jar(WorkflowContextHandler.class);
		if(jarFile.isPresent()) {
			try {
				ResourceCopy.copyResourceDirectory(jarFile.get(), resPath, new File(directory));
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		} else {
			URL resourcesUrl = WorkflowContextHandler.class.getResource("/" + resPath);
	        if (resourcesUrl != null)
	        {
	        	try {
	        		FileUtils.copyDirectory(new File(resourcesUrl.getPath()), new File(directory));
	        	} catch (Exception e) {
	        		throw new RuntimeException(e);
	        	}
	        }
		}
		
		/*if(persistHtmlFiles) {
			File tmpfolder = new File(FileUtils.getTempDirectory(), "out");
			File[] existingFiles = tmpfolder.listFiles(new FilenameFilter() {
				public boolean accept(File folder, String name) {
					return name.endsWith(".html");
				}
			});
			for (File file : existingFiles) {
				try {
					FileUtils.moveFile(file, new File(directory));
				} catch (IOException e) {
				}
			}
			try {
				FileUtils.deleteDirectory(tmpfolder);
			} catch (IOException e) {
			}
		}*/
	}
}
 @XStreamAlias("gatf-testdata-config")
@JsonAutoDetect(getterVisibility=Visibility.NONE, fieldVisibility=Visibility.ANY, isGetterVisibility=Visibility.NONE)
@JsonInclude(value = Include.NON_NULL)
public class GatfTestDataConfig implements Serializable {

	private static final long serialVersionUID = 1L;
	
	@XStreamConverter(value=MapKeyValueCustomXstreamConverter.class)
	private Map<String, String> globalVariables;
	
	private List<String> compareEnvBaseUrls;
	
	private List<GatfTestDataSource> dataSourceList;

	private List<GatfTestDataProvider> providerTestDataList;
	
	private List<GatfTestDataSourceHook> dataSourceHooks;
	
	private List<GatfTestDataSource> dataSourceListForProfiling;

	public Map<String, String> getGlobalVariables() {
		return globalVariables;
	}

	public void setGlobalVariables(Map<String, String> globalVariables) {
		this.globalVariables = globalVariables;
	}

	public List<GatfTestDataProvider> getProviderTestDataList() {
		return providerTestDataList;
	}

	public void setProviderTestDataList(
			List<GatfTestDataProvider> providerTestDataList) {
		this.providerTestDataList = providerTestDataList;
	}

	public List<String> getCompareEnvBaseUrls() {
		return compareEnvBaseUrls;
	}

	public void setCompareEnvBaseUrls(List<String> compareEnvBaseUrls) {
		this.compareEnvBaseUrls = compareEnvBaseUrls;
	}

	public List<GatfTestDataSource> getDataSourceList() {
		return dataSourceList;
	}

	public void setDataSourceList(List<GatfTestDataSource> dataSourceList) {
		this.dataSourceList = dataSourceList;
	}

	public List<GatfTestDataSourceHook> getDataSourceHooks() {
		return dataSourceHooks;
	}

	public void setDataSourceHooks(List<GatfTestDataSourceHook> dataSourceHooks) {
		this.dataSourceHooks = dataSourceHooks;
	}

	public List<GatfTestDataSource> getDataSourceListForProfiling() {
		return dataSourceListForProfiling;
	}

	public void setDataSourceListForProfiling(List<GatfTestDataSource> dataSourceListForProfiling) {
		this.dataSourceListForProfiling = dataSourceListForProfiling;
	}
}
 @XStreamAlias("gatf-testdata-provider")
@JsonAutoDetect(getterVisibility=Visibility.NONE, fieldVisibility=Visibility.ANY, isGetterVisibility=Visibility.NONE)
@JsonInclude(value = Include.NON_NULL)
public class GatfTestDataProvider implements Serializable {

	private static final long serialVersionUID = 1L;
	
	private String dataSourceName;
	
	private String providerName;
	
	private String providerClass;
	
	private String sourceProperties;
	
	private String providerProperties;
	
	private String queryStr;
	
	private Boolean enabled;
	
	protected String[] args;
	
	private Boolean live;

	public String getProviderName() {
		return providerName;
	}

	public void setProviderName(String providerName) {
		this.providerName = providerName;
	}

	public Boolean isEnabled() {
		return enabled!=null && enabled;
	}

	public void setEnabled(Boolean enabled) {
		this.enabled = enabled;
	}

	public String getDataSourceName() {
		return dataSourceName;
	}

	public void setDataSourceName(String dataSourceName) {
		this.dataSourceName = dataSourceName;
	}

	public String getProviderProperties() {
		return providerProperties;
	}

	public void setProviderProperties(String providerProperties) {
		this.providerProperties = providerProperties;
	}

	public String getSourceProperties() {
		return sourceProperties;
	}

	public void setSourceProperties(String sourceProperties) {
		this.sourceProperties = sourceProperties;
	}

	public String getQueryStr() {
		return queryStr;
	}

	public void setQueryStr(String queryStr) {
		this.queryStr = queryStr;
	}

	public String[] getArgs() {
		return args;
	}

	public void setArgs(String[] args) {
		this.args = args;
	}

	public String getProviderClass() {
		return providerClass;
	}

	public void setProviderClass(String providerClass) {
		this.providerClass = providerClass;
	}

	public Boolean isLive() {
		return live!=null && live;
	}

	public void setLive(Boolean live) {
		this.live = live;
	}

	public GatfTestDataProvider(){}

	public GatfTestDataProvider(GatfTestDataProvider other) {
		super();
		this.dataSourceName = other.dataSourceName;
		this.providerName = other.providerName;
		this.providerClass = other.providerClass;
		this.sourceProperties = other.sourceProperties;
		this.providerProperties = other.providerProperties;
		this.queryStr = other.queryStr;
		this.enabled = other.enabled;
		if(other.args!=null) {
		    this.args = (String[])Arrays.asList(other.args).toArray(new String[other.args.length]);
		}
		this.live = other.live;
	}
}
 @XStreamAlias("gatf-testdata-source")
@JsonAutoDetect(getterVisibility=Visibility.NONE, fieldVisibility=Visibility.ANY, isGetterVisibility=Visibility.NONE)
@JsonInclude(value = Include.NON_NULL)
public class GatfTestDataSource implements Serializable {

	private static final long serialVersionUID = 1L;
	
	private String dataSourceName;
	
	private String dataSourceClass;
	
	private int poolSize = 1;
	
	private long newResourceCheckoutTimeMs = 1000;
	
	private String[] args;

	public String getDataSourceName() {
		return dataSourceName;
	}

	public void setDataSourceName(String dataSourceName) {
		this.dataSourceName = dataSourceName;
	}

	public String[] getArgs() {
		return args;
	}

	public void setArgs(String[] args) {
		this.args = args;
	}

	public String getDataSourceClass() {
		return dataSourceClass;
	}

	public void setDataSourceClass(String dataSourceClass) {
		this.dataSourceClass = dataSourceClass;
	}

	public int getPoolSize() {
		return poolSize;
	}

	public void setPoolSize(int poolSize) {
		this.poolSize = poolSize;
	}
	
	public long getNewResourceCheckoutTimeMs() {
		return newResourceCheckoutTimeMs;
	}

	public void setNewResourceCheckoutTimeMs(long newResourceCheckoutTimeMs) {
		this.newResourceCheckoutTimeMs = newResourceCheckoutTimeMs;
	}
}
 @XStreamAlias("gatf-testdata-source-hook")
@JsonAutoDetect(getterVisibility=Visibility.NONE, fieldVisibility=Visibility.ANY, isGetterVisibility=Visibility.NONE)
@JsonInclude(value = Include.NON_NULL)
public class GatfTestDataSourceHook implements Serializable {

	private static final long serialVersionUID = 1L;
	
	private String hookName;
	
	private String hookClass;
	
	private String dataSourceName;
	
	private String[] queryStrs;
	
	private boolean executeOnStart;
	
	private boolean executeOnShutdown;
	
	public String getHookName() {
		return hookName;
	}

	public void setHookName(String hookName) {
		this.hookName = hookName;
	}

	public String getDataSourceName() {
		return dataSourceName;
	}

	public void setDataSourceName(String dataSourceName) {
		this.dataSourceName = dataSourceName;
	}

	public String[] getQueryStrs() {
		return queryStrs;
	}

	public void setQueryStrs(String[] queryStrs) {
		this.queryStrs = queryStrs;
	}

	public String getHookClass() {
		return hookClass;
	}

	public void setHookClass(String hookClass) {
		this.hookClass = hookClass;
	}

	public boolean isExecuteOnStart() {
		return executeOnStart;
	}

	public void setExecuteOnStart(boolean executeOnStart) {
		this.executeOnStart = executeOnStart;
	}

	public boolean isExecuteOnShutdown() {
		return executeOnShutdown;
	}

	public void setExecuteOnShutdown(boolean executeOnShutdown) {
		this.executeOnShutdown = executeOnShutdown;
	}
}
 public class ApiPlugin {

    public static Object api(Object[] args) throws Exception {
        String testname = args[0].toString();
        String testcaseFileName = "selenium-apis.xml";
        if(testname.indexOf("@")!=-1) {
            testcaseFileName = testname.substring(0, testname.indexOf("@"));
            testname = testname.substring(testname.indexOf("@")+1);
        }
        
        GatfConfigToolUtil mojo = new GatfConfigToolUtil();
        mojo.setContext((AcceptanceTestContext)args[args.length-1]);
        
        int index = (Integer)args[args.length-2];
        
        GatfReportsHandler handler = new GatfReportsHandler(mojo, null);
        mojo.setRootDir(mojo.getContext().getGatfExecutorConfig().getTestCasesBasePath());
        Object[] out = handler.executeTest(mojo.getContext().getGatfExecutorConfig(), null, "playTest", testcaseFileName, testname, false, 
        		false, index, true, 0, false, null);
        TestCaseReport report = (TestCaseReport)out[3];
        
        System.out.println("Executed api " + testname + "@" + testcaseFileName);
        System.out.println(report);
        
        if(report!=null && !report.getStatus().equalsIgnoreCase("failed")) {
            if(report.getResponseContentType()!=null) {
                if(report.getResponseContentType().indexOf("xml")!=-1) {
                    return XmlPlugin.read(new Object[]{report.getResponseContent()});
                } else if(report.getResponseContentType().indexOf("json")!=-1) {
                    return JsonPlugin.read(new Object[]{report.getResponseContent()});
                }
            }
        }
        
        return null;
    }
    
    public static String[] toSampleSelCmd() {
    	return new String[] {
    		"API Plugin",
    		"\tplugin api {test-name}@{optional test-case-file-name}",
    		"Examples :-",
    		"\tplugin api api-name",
    		"\tplugin api api-name@test-case-file-path",
        };
    }
} public class CurlPlugin {

    public static boolean isParameterizeFirstSetParam(String arg, int index) {
        if(index==1) {
            return false;
        }
        return true;
    }
    
    @SuppressWarnings("unchecked")
    public static Object execute(Object[] args) throws Exception {
        String method = args[0].toString();
        String url = args[1].toString();
        
        OkHttpClient client = new OkHttpClient.Builder().build();
        Request.Builder rbuilder = new Request.Builder();
        rbuilder.url(url);
        
        RequestBody body = null;
        
        List<List<Object>> lst = (List<List<Object>>)args[args.length-3];
        
        if(CollectionUtils.isNotEmpty(lst))
        {
            List<Object> iheaders = lst.get(0);
            if(iheaders.size()>0) {
                for (Object o : iheaders) {
                    if(o instanceof String) {
                        String name = o.toString().substring(0, o.toString().indexOf("="));
                        String value = o.toString().substring(o.toString().indexOf("=")+1);
                        rbuilder.addHeader(name, value);
                    }
                }
            }
            
            String content = null;
            if(method.equalsIgnoreCase("post") || method.equalsIgnoreCase("put")) {
                content = lst.get(1).get(0).toString();
                body = RequestBody.create(content, null);
            }
        }

        if(method.toUpperCase().equals("post") || method.toUpperCase().equals("put")) {
			if(body==null) {
				body = RequestBody.create(StringUtils.EMPTY, null);
			}
		}
        Response response = client.newCall(rbuilder.method(method.toUpperCase(), body).build()).execute();
        
        List<String> cookies = new ArrayList<String>();
        Map<String, List<String>> headers = new HashMap<String, List<String>>();
        for (String name : response.headers().names()) {
        	if(name.equalsIgnoreCase("Set-Cookie")) {
        		cookies.addAll(response.headers().values(name));   
        	} else {
        		headers.put(name, response.headers().values(name));
        	}
        }
        
        Map<String, Object> resp = new HashMap<String, Object>();
        resp.put("statusCode", response.code());
        resp.put("statusText", response.message());
        resp.put("body", Base64.getEncoder().encodeToString(response.body().bytes()));
        resp.put("contentType", response.body().contentType().toString());
        resp.put("headers", headers);
        resp.put("cookies", cookies);
        
        return WorkflowContextHandler.OM.writeValueAsString(resp);
    }
    
    public static String[] toSampleSelCmd() {
    	return new String[] {
    		"Curl Plugin",
    		"\tplugin curl get|put|post|delete {url}\n\t{\n\t\t[\n\t\t\theader=value\n\t\t]\n\t\tcontent-body\n\t}",
    		"Examples :-",
    		"\tplugin curl get http://abc.com",
    		"\tplugin curl post http://abc.com\n\t{\n\t\t[\n\t\t\tContent-Type=application/xml\n\t\t]\n\t\t<abc>abc</abc>\n\t}",
        };
    }
} public class JsonPlugin {

    public static Object read(Object[] args) throws Exception {
        if(args.length>0 && args[0] instanceof String) {
            return WorkflowContextHandler.OM.readTree(args[0].toString());
        }
        return null;
    }
    
    public static Object write(Object[] args) throws Exception {
        if(args.length==4) {
            if(args[0] instanceof List || args[0] instanceof Set || args[0] instanceof Map) {
                return WorkflowContextHandler.OM.writeValueAsString(args[0]);
            } else {
                return WorkflowContextHandler.OM.writeValueAsString(args[0]);
            }
        } else if(args.length==5 && args[1] instanceof String) {
            if(args[0] instanceof List || args[0] instanceof Set || args[0] instanceof Map) {
                WorkflowContextHandler.OM.writeValue(new File(args[1].toString()), args[0]);
            } else {
                WorkflowContextHandler.OM.writeValue(new File(args[1].toString()), args[0]);
            }
            return true;
        }
        return null;
    }
    
    public static Object path(Object[] args) throws Exception {
        if(args.length==5) {
            return JsonPath.read(args[1].toString(), (String)args[0]);
        }
        return null;
    }
    
    public static String[] toSampleSelCmd() {
    	return new String[] {
    		"JSON Plugin",
    		"\tjsonread {json-text}",
    		"\tjsonwrite {optional-path-to-file} {jackson-annotated-json-object-or-map-list-set}",
    		"\tjsonpath {json-text} {json-path-string}",
    		"Examples :-",
    		"\tjsonread '{\"a\": \"abc\", \"b\": 1}'",
    		"\tjsonwrite '/path/to/file.json' $jsonObjectVar",
    		"\tjsonpath '{\"a\": \"abc\", \"b\": 1}' '$.a'",
        };
    }
} @SuppressWarnings("serial")
public class XmlPlugin {
    
    private static XmlMapper xmlMapper = new XmlMapper();
    
    static {
        xmlMapper.registerModule(new SimpleModule().addDeserializer(JsonNode.class, new JsonNodeDeserializer() {
            @Override
            public JsonNode deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
                String rootName = ((FromXmlParser)p).getStaxReader().getLocalName();
                return ctxt.getNodeFactory().objectNode().set(rootName, super.deserialize(p, ctxt));
            }
        }));
    }

    public static Object read(Object[] args) throws Exception {
        if(args.length>0 && args[0] instanceof String) {
            return xmlMapper.readTree(args[0].toString());
        }
        return null;
    }
    
    public static Object write(Object[] args) throws Exception {
        if(args.length==4) {
            if(args[0] instanceof List || args[0] instanceof Set || args[0] instanceof Map) {
                String ret = xmlMapper.writeValueAsString(args[0]).replaceFirst("<ObjectNode xmlns=\"\">", "");
                return ret.substring(0, ret.length()-13);
            } else {
                String ret = xmlMapper.writeValueAsString(args[0]).replaceFirst("<ObjectNode xmlns=\"\">", "");
                return ret.substring(0, ret.length()-13);
            }
        } else if(args.length==5 && args[1] instanceof String) {
            if(args[0] instanceof List || args[0] instanceof Set || args[0] instanceof Map) {
                xmlMapper.writeValue(new File(args[1].toString()), args[0]);
            } else {
                xmlMapper.writeValue(new File(args[1].toString()), args[0]);
            }
            return true;
        }
        return null;
    }
    
    public static Object path(Object[] args) throws Exception {
        if(args.length==5) {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            if(args[1] instanceof JsonNode) {
                String ret = xmlMapper.writeValueAsString(args[1]).replaceFirst("<ObjectNode xmlns=\"\">", "");
                ret = ret.substring(0, ret.length()-13);
                Document doc = builder.parse(new ByteArrayInputStream(ret.getBytes()));
                return getNodeValue(doc, (String)args[0]);
            } else {
                Document doc = builder.parse(new ByteArrayInputStream(args[1].toString().getBytes()));
                return getNodeValue(doc, (String)args[0]);
            }
        }
        return null;
    }
    
    public static String[] toSampleSelCmd() {
    	return new String[] {
    		"XML Plugin",
    		"\txmlread {xml-text}",
    		"\txmlwrite {optional-path-to-file} {xml-object-or-map-list-set}",
    		"\txmlpath {xml-text} {xpath-string}",
    		"Examples :-",
    		"\txmlread '<o><a>abc</a><b>1</b></o>'",
    		"\txmlwrite '/path/to/file.xml' $xmlObjectVar",
    		"\txmlpath '<o><a>abc</a><b>1</b></o>' '/o/a'",
        };
    }
    
    protected static String getNodeValue(Object intObj, String node) throws Exception {
        NodeList xmlNodeList = null;
        String xmlValue = null;
        try
        {
            xmlNodeList = getNodeByXpath(node, (Document)intObj);
            xmlValue = getXMLNodeValue(xmlNodeList.item(0));
        }
        catch (Exception e)
        {
        }
        //Assert.assertTrue("Expected Node " + node + " is null", xmlNodeList!=null && xmlNodeList.getLength()>0);
        return xmlValue;
    }
    
    public static String getXMLNodeValue(Node node)
    {
        String xmlValue = null;
        try
        {
            if(node.getNodeType()==Node.TEXT_NODE 
                    || node.getNodeType()==Node.CDATA_SECTION_NODE)
            {
                xmlValue = node.getNodeValue();
            }
            else if(node.getNodeType()==Node.ATTRIBUTE_NODE)
            {
                xmlValue = ((Attr)node).getValue();
            }
            else if(node.getNodeType()==Node.ELEMENT_NODE
                    && node.getChildNodes().getLength()>=1
                    && (node.getFirstChild().getNodeType()==Node.TEXT_NODE
                    || node.getFirstChild().getNodeType()==Node.CDATA_SECTION_NODE))
            {
                xmlValue = node.getFirstChild().getNodeValue();
            }
        }
        catch (Exception e)
        {
        }
        return xmlValue;
    }
    
    protected static NodeList getNodeByXpath(String xpathStr, Document xmlDocument) throws XPathExpressionException
    {
        if(xpathStr.charAt(0)!='/')
            xpathStr = "/" + xpathStr;
        XPath xPath =  XPathFactory.newInstance().newXPath();
        NodeList xmlNodeList = (NodeList) xPath.compile(xpathStr).evaluate(xmlDocument, XPathConstants.NODESET);
        return xmlNodeList;
    }
}
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Stack;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.openqa.selenium.Keys;
import org.reflections.Reflections;
import com.gatf.executor.core.AcceptanceTestContext;
import com.gatf.executor.core.GatfExecutorConfig;
import com.gatf.executor.core.WorkflowContextHandler;
import com.gatf.executor.dataprovider.GatfTestDataConfig;
import com.gatf.executor.dataprovider.GatfTestDataProvider;
import com.gatf.executor.dataprovider.GatfTestDataSource;
import com.gatf.executor.dataprovider.GatfTestDataSourceHook;
import com.gatf.selenium.plugins.ApiPlugin;
import com.gatf.selenium.plugins.CurlPlugin;
import com.gatf.selenium.plugins.JsonPlugin;
import com.gatf.selenium.plugins.XmlPlugin;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

                c += avn1 + ".add("+avn2+");\n";
            }
            c += vn + " = pluginize(\""+name+"\", \""+plugins.get(name)+"\", "+avn+", "+avn1+")";
            return c;
        }
        String javacode() {
            String avn = state.alvarname();
            String c = "List<String> "+avn+" = new java.util.ArrayList<String>();\n";
            for (String i : in) {
                c += avn + ".add(\""+esc(i)+"\");\n";
            }
            String avn1 = state.alvarname();
            c += "List<List<String>> "+avn1+" = new java.util.ArrayList<List<String>>();\n";
            for (String[] i : in1) {
                String avn2 = state.alvarname();
                c += "List<String> "+avn2+" = new java.util.ArrayList<String>();\n";
                for (String s : i) {
                    c += avn2 + ".add(\""+esc(s)+"\");\n";
                }
                c += avn1 + ".add("+avn2+");\n";
            }
            c += "pluginize(\""+name+"\", \""+plugins.get(name)+"\", "+avn+", "+avn1+");\n";
            return c;
        }
        public PluginCommand(String info, Object[] cmdDetails, CommandState state) {
            super(cmdDetails, state);
            String[] parts = info.trim().split("[\t ]+");
            if(parts.length>0) {
                name = unSantizedUnQuoted(parts[0], state);
                if(!plugins.containsKey(name)) {
                    throwError(cmdDetails, new RuntimeException("Plugin not found with name " + name));
                }
                for (int i = 1; i < parts.length; i++) {
                    in.add(unSantizedUnQuoted(parts[i], state));
                }
                for (int i = 0; i < children.size(); i++) {
                    if(children.get(i) instanceof ValueListCommand) {
                        ValueListCommand vlc = (ValueListCommand)children.get(i);
                        String[] tm = new String[vlc.children.size()];
                        int c = 0;
                        for (Command vc : vlc.children) {
                            tm[c++] = unSantizedUnQuoted(((ValueCommand)vc).value, state); 
                        }
                        in1.add(tm);
                    } else {
                        in1.add(new String[]{unSantizedUnQuoted(((ValueCommand)children.get(i)).value, state)});
                    }
                }
            } else {
                //excep
            }
        }
        public void reconcile() {
            for (int i = 0; i < children.size(); i++) {
                if(children.get(i) instanceof ValueListCommand) {
                    ValueListCommand vlc = (ValueListCommand)children.get(i);
                    String[] tm = new String[vlc.children.size()];
                    int c = 0;
                    for (Command vc : vlc.children) {
                        tm[c++] = unSantizedUnQuoted(((ValueCommand)vc).value, state); 
                    }
                    in1.add(tm);
                } else {
                    in1.add(new String[]{unSantizedUnQuoted(((ValueCommand)children.get(i)).value, state)});
                }
            }
        }
        public static String[] toSampleSelCmd() {
        	List<String> cmdl = new ArrayList<String>();
        	for (String name : plugins.keySet()) {
				String signature = plugins.get(name);
		        try
		        {
		            String[] parts = signature.split("@");
		            String clsname = parts[0].trim();

		            Class<?> cls = Class.forName(clsname);
		            Method meth = cls.getMethod("toSampleSelCmd", new Class[]{});
		            
		            String[] cmds = (String[])meth.invoke(null, new Object[] {});
		            cmdl.addAll(Arrays.asList(cmds));
		        }
		        catch (Exception e)
		        {
		        }
			}
            return cmdl.toArray(new String[cmdl.size()]);
        }
    }
    
    public static String validateSel(String[] args) throws Exception {
        GatfExecutorConfig config = getConfig(args.length>2?args[2].trim():"gatf-config.xml", args.length>3?args[3].trim():"/workdir");
        config.setSeleniumLoggerPreferences("browser(OFF),client(OFF),driver(OFF),performance(OFF),profiler(OFF),server(OFF)");
        for (SeleniumDriverConfig selConf : config.getSeleniumDriverConfigs())
        {
            if(selConf.getDriverName()!=null) {
                System.setProperty(selConf.getDriverName(), selConf.getPath());
            }
        }
        
        AcceptanceTestContext c = new AcceptanceTestContext();
        c.setGatfExecutorConfig(config);
        c.validateAndInit(true);
        c.getWorkflowContextHandler().initializeSuiteContext(1);
        
        if(args[1].indexOf(File.separator)==-1) {
        	args[1] = "/workdir/"+args[1];
        }
    	
        Object[] retvals = new Object[5];
        try {
        	Map<Integer, Object[]> selToJavaLineMap = new HashMap<Integer, Object[]>();
            SeleniumTest dyn = SeleniumCodeGeneratorAndUtil.getSeleniumTest(args[1], Command.class.getClassLoader(), c, retvals, config, args.length>4?args[4].trim().equalsIgnoreCase("true"):false, selToJavaLineMap);
            System.out.println(dyn!=null?"SUCCESS":"FAILURE");
            if(dyn!=null) {
            	return "{\"status\": \"SUCCESS\"}";
            }
        	Map<String, String> mpe = new HashMap<String, String>();
        	mpe.put("status", "FAILURE");
        	mpe.put("error", retvals[4].toString());

            return WorkflowContextHandler.OM.writeValueAsString(mpe);
