Unable to Create Multiple drivers + parallel execution + appium

I am trying to develop an appium framework,As a part of it i am trying for parallel execution . I am able to run with single thread properly but its getting more challenging when it comes to multi thread.

I initially created all appium servers and capabilites. But i am not sure how can i assign each server url to driver. I tried below approach . But it didnt work. Here is my code.

public class TestBase1 {

private Properties projectProperties;

private AppiumDriver driver;
private AppiumDriverLocalService appiumservice;

private HashMap <String,Integer>appiumServerURLs;
private HashMap<DesiredCapabilities,String> appiumServerCapabilities;


//Load the Properties file to the Properties Object
private void loadProperties() {
    try {
        InputStream inputStream = getClass().getClassLoader().getResourceAsStream("./config/config.properties");
        projectProperties = new Properties();
        projectProperties.load(inputStream);
    } catch (Exception ex) {
        ex.printStackTrace();
    }

}

private void setCapabilities() {
    appiumServerCapabilities = new HashMap<DesiredCapabilities, String>();
    String devices[] = {"4618c629","73d73351"};
    for(String str:devices) {
        DesiredCapabilities capabilities = new DesiredCapabilities();
        String DEVICE_NAME = projectProperties.getProperty("DEVICE_NAME");
        String BROWSER_NAME = projectProperties.getProperty("BROWSER_NAME");
        String APP_TYPE = projectProperties.getProperty("APPLICATION_TYPE");
        if (APP_TYPE.equalsIgnoreCase("Web")) {
            capabilities.setCapability("noReset", "false");
            capabilities.setCapability(MobileCapabilityType.UDID,str);
            capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, DEVICE_NAME);
            capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, BROWSER_NAME);
        } else {

        }
        appiumServerCapabilities.put(capabilities,"NULL");
    }
}

@BeforeSuite
public void initProject() {
    loadProperties();
    setCapabilities();

}

@BeforeTest
public void beforeTest() {
    launchAppiumServer();
}
@AfterTest
public void AfterTest() {
    stopAppiumServer();
}

@BeforeMethod
public void beforeTestExecution() {
    createDriver();
}

public void launchAppiumServer(){
    appiumServerURLs = new HashMap<String, Integer>();
    for(Map.Entry<DesiredCapabilities,String> capabilities:appiumServerCapabilities.entrySet()) {
        AppiumServiceBuilder builder;
        //Build the Appium service
        builder = new AppiumServiceBuilder();
        builder.withIPAddress("127.0.0.1");
        builder.usingAnyFreePort();
        builder.withCapabilities(capabilities.getKey());
        builder.withArgument(GeneralServerFlag.SESSION_OVERRIDE);
        builder.withArgument(GeneralServerFlag.LOG_LEVEL, "error");
        appiumservice = AppiumDriverLocalService.buildService(builder);
        appiumservice.start();
        System.out.println("Server Started at :"+appiumservice.getUrl().toString());
        appiumServerURLs.put(appiumservice.getUrl().toString(),0);
        capabilities.setValue(appiumservice.getUrl().toString());
    }
}

public void stopAppiumServer(){
   appiumservice.stop();
}
public void createDriver() {

    String strDriverType = projectProperties.getProperty("DEVICE_PLATFORM");
    try {
        boolean driverAvailable = false;
        if (strDriverType != null) {
            if (strDriverType.equalsIgnoreCase("Android")) {
                while(!driverAvailable) {
                    for(Map.Entry<String,Integer> urlEntries:appiumServerURLs.entrySet()){
                        if(urlEntries.getValue()==0) {
                            DesiredCapabilities cap = null;
                            for(Map.Entry<DesiredCapabilities,String> capEntries:appiumServerCapabilities.entrySet()){
                                if(capEntries.getValue().toString().equals(urlEntries.getKey())){
                                    cap = capEntries.getKey();
                                }
                            }
                            driver = new AndroidDriver(new URL(urlEntries.getKey().toString()), cap);
                            System.out.println("Driver Created for :"+urlEntries.getKey().toString());
                            urlEntries.setValue(1);
                            driverAvailable=true;
                            break;

                        }
                    }
                }
            }
            if (strDriverType.equalsIgnoreCase("iOS")) {

            }
        } else {
            System.out.println("Device Platform Undefined !");

        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

public HomePage launchApp() {
    String url = projectProperties.getProperty("TEST_URL");
    driver.get(url);
    return new HomePage(driver);
}

@AfterMethod
public void afterTestExecution() {
    DesiredCapabilities cap = (DesiredCapabilities) driver.getCapabilities();
    String appiumURL = null;
    for (Map.Entry<DesiredCapabilities, String> capEntries : appiumServerCapabilities.entrySet()) {
        if (capEntries.getKey().getCapability(MobileCapabilityType.UDID).equals(cap.getCapability(MobileCapabilityType.UDID))) {
            appiumURL = capEntries.getValue();
        }

    }
    for (Map.Entry<String, Integer> urlEntries : appiumServerURLs.entrySet()) {
        if (urlEntries.getKey().toString().equals(appiumURL)) {
            urlEntries.setValue(0);
        }

    }
    driver.quit();
}

}

and my test case has following code

 */

public class LoginTest extends TestBase1 {

@Test
public void login()
{
    launchApp().clickSigninLink()
               .enterCrendentialsandLogin();
}
@Test
public void setLocation()
{
   //some automation code

}

@Test
public void setHomeLocation()
{
    //some automation code
}

}
and my testng.xml is configured for 2 threads.

On executing above code i getting session cannot be created or null , some times its opening browser in one device but immediately failing.

I am also not sure how to stop Mulitple appium servers.

Appreciate your help.

Thanks.

Parallel execution in TestNg could be defined at class level as well as at method level. Based on that you need to declare the thread local to hold the driver instance specific to method or class.

Thanks for response. I am using Method level for parallel execution in TestNG.xml. But unfortunately i am not sure how to maintain driver object for multithread.

If you are using Method level parallelism then you need to initiate the thread in Before method by including @BeforeMethod annotation of TestNg. Where each of the TestMethod would execute this BeforeMethod prior to execution of the TestMethod.

I hope this would help you.

Can you please provide a sample snippet.
Considering i am having 3 appium server url’s http://127.0.0.1:4723 , http://127.0.0.1:4724 , http://127.0.0.1:4725 and 3 capabiliies for each device in an array/Hashmap.

Appreciate your support.

Thanks