How to use ThreadLocal in Parallel Execution Appium?

It worked fine before when I ran only one, but in parallel execution dosen’t run.
Created a class called AppiumDriverManager and used ThreadLocal.
But it dosen’t run…

  1. java -jar selenium-server-standalone-3.141.59.jar -role hub
  2. Set up Appium(server port, node config file path, allow session override, bootstrap port) and Run
  3. Check http://localhost:4444/grid/console

Here is my code example.

package appiumset;

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;

public class AppiumDriverManager {
	
	
	public static final ThreadLocal<AppiumDriver<MobileElement>> appiumDriver = new ThreadLocal<>();
    
	
	
	public static synchronized void setDriver(AppiumDriver<MobileElement> driver) { 
		appiumDriver.set(driver);
	}
	   
    public static synchronized AppiumDriver<MobileElement> getDriver() {
        return appiumDriver.get();
    }

}

package appiumset;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Parameters;

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;
import io.appium.java_client.remote.AndroidMobileCapabilityType;
import io.appium.java_client.remote.MobileCapabilityType;

public class _2_Deviceinfo extends AppiumDriverManager {

@Parameters({“device”, “apppackage”, “activity”,“version”,“appiumServer” , “systemPort”, “platformName”})
@BeforeTest
public synchronized void deviceSetUp(String device, String apppackage, String activity, String version, String appiumServer, String systemPort, String platformName) throws InterruptedException, MalformedURLException, InterruptedException {
System.out.println(“****************************************”);
System.out.println(“Setting up device and desired capabilities”);

  DesiredCapabilities cap = new DesiredCapabilities();
  
  
  
  AppiumDriver<MobileElement> driver = AppiumDriverManager.getDriver();
  
  URL url = new URL(appiumServer);
  

  AppiumDriverManager.setDriver(new AppiumDriver<MobileElement>(url, cap));
  

  
  cap.setCapability(MobileCapabilityType.DEVICE_NAME, device);
  cap.setCapability(MobileCapabilityType.UDID, device);
  cap.setCapability(AndroidMobileCapabilityType.SYSTEM_PORT, systemPort);
  cap.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 120);

  cap.setCapability(MobileCapabilityType.PLATFORM_NAME, platformName);
  //cap.setCapability(MobileCapabilityType., BrowserType.ANDROID);
  cap.setCapability(MobileCapabilityType.PLATFORM_VERSION, version);
  

  //"com.hanwha.lifeplus.tribes.app.qa"
  cap.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, apppackage);
  //"com.hanwha.lifeplus.presentation.ui.HomeActivity"
  cap.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, activity);

  cap.setCapability("automationName", "UiAutomator2");

  cap.setCapability("noReset","false");
  cap.setCapability("FullReset","true");

  cap.setCapability("APP_WAIT_ACTIVITY", "*");
  cap.setCapability("autowebview","false");
  
  
  driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);

}

@AfterTest
public void tearDown() throws Exception
{
if (AppiumDriverManager.getDriver() != null) {
AppiumDriverManager.getDriver().quit();
}
}
}

package appiumset;

import java.util.NoSuchElementException;

import org.openqa.selenium.StaleElementReferenceException;
import org.testng.annotations.Test;

public class _1_Appstart extends _2_Deviceinfo {

@SuppressWarnings(“unchecked”)
@Test
public void Appstart() throws InterruptedException, NullPointerException, NoSuchElementException, StaleElementReferenceException {

  _3_Onboarding a03 = new _3_Onboarding();
  _4_Tribeslist a04 = new _4_Tribeslist();
  _5_Tribesdetail a05 = new _5_Tribesdetail();
  _6_Tribeshome a06 = new _6_Tribeshome();
  _7_Settings a07 = new _7_Settings();
  _8_Eventtribes a08 = new _8_Eventtribes();
  _9_Logout a09 = new _9_Logout();

  
  
  
  try {
  	a03.onboarding();
  	
  	
  	for(int i=1; i<=100; i++) {

  		
  		
  		if(i <= 100) {
  			System.out.println(" <<<<< " + i + " repeat.>>>> ");
  		
  		}else if(i > 100) {
  			System.out.println( i + " repeat complete");
  		}
  		a04.tribeslist();
  		a05.tribesdetail();
  		a06.tribeshome();
  		a07.settings();
  		a08.Eventtribes();
  		a09.Logout();
  	}
  	
  	
  
  }catch(Exception exp) {
  	System.out.println(exp.getCause());
  	System.out.println(exp.getMessage());
  	exp.printStackTrace();	
  }

}
}

<?xml version="1.0" encoding="UTF-8"?>
	<!-- S22 : 192.168.0.100:5554 / R3CT201CM7A-->
  <test name="RealDevice Test1">
  	<parameter name="device" value="R3CT201CM7A"></parameter>
  	<parameter name="platformName" value="Android"></parameter>
  	<parameter name="apppackage" value="apppackage"></parameter>	
  	<parameter name="activity" value="activity"></parameter>	
  	<parameter name="version" value="12"></parameter>	
  	<parameter name="systemPort" value="8201"/>
  	<parameter name="appiumServer" value="http://0.0.0.0:4723/wd/hub"></parameter>
  	<classes>
  		<class name="appiumset._1_Appstart"></class>
  	</classes>
  </test>
  <test name="RealDevice Test2">
  <!-- S10 : 192.168.0.130:5555 / R39M20CG24R-->
  	<parameter name="device" value="R39M20CG24R"></parameter>	
  	<parameter name="platformName" value="Android"></parameter>
  	<parameter name="apppackage" value="apppackage"></parameter>	
  	<parameter name="activity" value="activity"></parameter>	
  	<parameter name="version" value="11"></parameter>	
  	<parameter name="systemPort" value="8202"/>
  	<parameter name="appiumServer" value="http://0.0.0.0:5000/wd/hub"></parameter>
  	<classes>
  		<class name="appiumset._1_Appstart"></class>
  	</classes>
  </test>
   <!-- Test -->
</suite> <!-- Suite -->

{
“capabilities”:
[
{
“browserName”: “Android”,
“platformVersion”: “12”,
“maxInstances”: 1,
“platformName”: “Android”,
“automationName”: “UiAutomator2”,
“systemPort”: “8201”,
“devcieName”: “R3CT201CM7A”
}
],
“configuration”:
{
“cleanUpCycle”: 2000,
“timeout”: 30000,
“proxy”: “org.openqa.grid.selenium.proxy.DefaultRemoteProxy”,
“url”: “http://0.0.0.0:4723/wd/hub”,
“host”: “0.0.0.0”,
“port”: 4723,
“maxSession”: 1,
“register”: true,
“registerCycle”: 5000,
“hubPort”: 4444,
“hubHost”: “192.168.0.88”,
“hubProtocol”: “http”
}
}

org.openqa.selenium.SessionNotCreatedException: Unable to create a new remote session. Please check the server log for more details. Original error: An unknown server-side error occurred while processing the command. Original error: You must include a platformName capability (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 77 milliseconds
Build info: version: ‘3.141.59’, revision: ‘e82be7d358’, time: ‘2018-11-14T08:17:03’
System info: host: ‘DESKTOP-S395I6J’, ip: ‘192.168.0.88’, os.name: ‘Windows 10’, os.arch: ‘amd64’, os.version: ‘10.0’, java.version: ‘17.0.4.1’
Driver info: driver.version: AppiumDriver
Build info: version: ‘3.141.59’, revision: ‘e82be7d358’, time: ‘2018-11-14T08:17:03’
System info: host: ‘DESKTOP-S395I6J’, ip: ‘192.168.0.88’, os.name: ‘Windows 10’, os.arch: ‘amd64’, os.version: ‘10.0’, java.version: ‘17.0.4.1’
Driver info: driver.version: AppiumDriver
at io.appium.java_client.remote.AppiumCommandExecutor$1.createSession(AppiumCommandExecutor.java:208)
at io.appium.java_client.remote.AppiumCommandExecutor.createSession(AppiumCommandExecutor.java:217)
at io.appium.java_client.remote.AppiumCommandExecutor.execute(AppiumCommandExecutor.java:239)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:552)
at io.appium.java_client.DefaultGenericMobileDriver.execute(DefaultGenericMobileDriver.java:42)
at io.appium.java_client.AppiumDriver.execute(AppiumDriver.java:1)
at org.openqa.selenium.remote.RemoteWebDriver.startSession(RemoteWebDriver.java:213)
at org.openqa.selenium.remote.RemoteWebDriver.(RemoteWebDriver.java:131)
at io.appium.java_client.DefaultGenericMobileDriver.(DefaultGenericMobileDriver.java:38)
at io.appium.java_client.AppiumDriver.(AppiumDriver.java:84)
at io.appium.java_client.AppiumDriver.(AppiumDriver.java:94)
at appiumset._2_Deviceinfo.deviceSetUp(_2_Deviceinfo.java:51)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:133)
at org.testng.internal.MethodInvocationHelper.invokeMethodConsideringTimeout(MethodInvocationHelper.java:62)
at org.testng.internal.ConfigInvoker.invokeConfigurationMethod(ConfigInvoker.java:385)
at org.testng.internal.ConfigInvoker.invokeConfigurations(ConfigInvoker.java:321)
at org.testng.TestRunner.invokeTestConfigurations(TestRunner.java:637)
at org.testng.TestRunner.beforeRun(TestRunner.java:627)
at org.testng.TestRunner.run(TestRunner.java:589)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:377)
at org.testng.SuiteRunner.access$000(SuiteRunner.java:28)
at org.testng.SuiteRunner$SuiteWorker.run(SuiteRunner.java:418)
at org.testng.internal.thread.ThreadUtil.lambda$execute$0(ThreadUtil.java:64)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at io.appium.java_client.remote.AppiumCommandExecutor$1.createSession(AppiumCommandExecutor.java:186)
… 30 more
Caused by: org.openqa.selenium.WebDriverException: An unknown server-side error occurred while processing the command. Original error: You must include a platformName capability (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 77 milliseconds
Build info: version: ‘3.141.59’, revision: ‘e82be7d358’, time: ‘2018-11-14T08:17:03’
System info: host: ‘DESKTOP-S395I6J’, ip: ‘192.168.0.88’, os.name: ‘Windows 10’, os.arch: ‘amd64’, os.version: ‘10.0’, java.version: ‘17.0.4.1’
Driver info: driver.version: AppiumDriver
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:214)
at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:166)
at org.openqa.selenium.remote.JsonWireProtocolResponse.lambda$errorHandler$0(JsonWireProtocolResponse.java:54)
at org.openqa.selenium.remote.HandshakeResponse.lambda$getResponseFunction$0(HandshakeResponse.java:30)
at org.openqa.selenium.remote.ProtocolHandshake.lambda$createSession$0(ProtocolHandshake.java:126)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
at java.base/java.util.Spliterators$ArraySpliterator.tryAdvance(Spliterators.java:1002)
at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:129)
at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:527)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:513)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:647)
at org.openqa.selenium.remote.ProtocolHandshake.createSession(ProtocolHandshake.java:128)
… 35 more