Selenium / Appium Parallel Execution using JUnit 4 - multithreading

Trying to execute appium tests parallely on multiple devices. Idea goes like initiating JUnitRunner class as parameterized (e.g. deviceList) that creates parallel thread per device. From runner, invoking TestSuite via JUnitCore.run. Problem is that instantiating driver in test cases need device name (probably from Runner class), but JUnitCore doesnt provide such option (to invoke Suite / Test class by instantiating it). Any help?
Code goes like: JUnitRunner.java
#RunWith(Parallelized.class) // extension of the Parameterized runner
public class JUTRunner {
private String device;
/**
* #param device
*/
public JUTRunner(String device) {
this.device = device;
}
/**
* #return
*/
#Parameters
public static Collection<Object[]> getParameters() {
List<String> deviceList = findAllDevices();
List<Object[]> parameters = new ArrayList<Object[]>(deviceList.size());
for (String device : deviceList) {
parameters.add(new Object[] { device });
}
return parameters;
}
/**
* #return
*/
private static List<String> findAllDevices() {
return DeviceList.getInstance().getDeviceList();
}
/**
* #throws InterruptedException
*/
#Test
public void testOnDevice() throws InterruptedException {
Result result = JUnitCore.runClasses(JUTSuite.class);
Result result = new JUnitCore().run(suite);
for (Failure failure : result.getFailures()) {
System.out.println(failure.toString());
}
if (result.wasSuccessful()) {
System.out.println("All tests finished successfully...");
}
}
}
And TestCase.java
public class MyTest extends TestCase {
protected String device;
protected AppiumDriver<MobileElement> driver;
private int deviceNum;
#Rule
public TestName testName = new TestName();
#Before
protected void setUp() throws Exception {
this.driver = new AndroidDriver(device).getDriver();
}
#Test
public void testLogin() {
System.out.println(testName.getMethodName() + device);
}
}

Related

LinkedHashMap issue... Anyone help me out

While executing this test case, following error I'm facing...
Please anyone suggests me in overcoming this issue.
AbortedJobImportTest
testAbortedJobAddedSuccessfullyToExcludedRun
Unknown entity: java.util.LinkedHashMap
org.hibernate.MappingException: Unknown entity: java.util.LinkedHashMap
at com.rsa.test.crawler.CrawlerTestBase.setUp(CrawlerTestBase.groovy:42)
at com.rsa.test.crawler.AbortedJobImportTest.setUp(AbortedJobImportTest.groovy:19)
/*
***
CrawlerTestBase
public class CrawlerTestBase extends GroovyTestCase {
static transactional = false;
def productsModel;
protected JenkinsJobCrawlerDTO jenkinsCrawlerDTO;
def jenkinsJobService;
def httpClientService;
def sessionFactory;
def productModelsService;
protected String JENKINS_URL = "http://10.101.43.253:8080/jenkins/";
protected String JENKINS_JOB_CONSTANT= "job";
protected String JUNIT_TEST_PARAMETERS = "type=junit";
protected String CUSTOM_JUNIT_SELENIUM_TEST_PARAMETERS = "type=selenium,outputfile=Custom-junit-report*";
protected String DEFAULT_PRODUCT = "AM";
public void setUp(){
deleteDataFromTables();
Date date = new Date();
productsModel = new ProductModel(product:DEFAULT_PRODUCT,jenkinsServers:"10.101.43.253",date:date);
if (productsModel.validate()) {
productsModel.save(flush:true);
log.info("Added entry for prodct model for "+DEFAULT_PRODUCT);
}
else {
productsModel.errors.allErrors.each { log.error it }
}
jenkinsCrawlerDTO = new JenkinsJobCrawlerDTO();
productModelsService.reinitialise();
sessionFactory.currentSession.save(flush:true);
sessionFactory.currentSession.clear();
}
public void tearDown(){
deleteDataFromTables();
}
protected void deleteDataFromTables(){
Set<String> tablesToDeleteData = new HashSet<String>();
tablesToDeleteData.add("ExcludedJenkinsRuns");
tablesToDeleteData.add("TestRuns");
tablesToDeleteData.add("ProductModel");
tablesToDeleteData.add("SystemEvents");
tablesToDeleteData.add("JenkinsJobsToCrawl");
tablesToDeleteData.add("TestSuitesInViewList");
tablesToDeleteData.add("JenkinsJobsToCrawl");
(ApplicationHolder.application.getArtefacts("Domain") as List).each {
if(tablesToDeleteData.contains(it.getName())){
log.info("Deleting data from ${it.getName()}");
it.newInstance().list()*.delete()
}
}
sessionFactory.currentSession.flush();
sessionFactory.currentSession.clear();
}
public void oneTimeSetUp(){
}
public void oneTimeTearDown(){
}
}
AbortedJobImportTest
public class AbortedJobImportTest extends CrawlerTestBase {
private String jobUrl = JENKINS_URL+JENKINS_JOB_CONSTANT+"/am-java-source-build/69/";
#Before
public void setUp() {
super.setUp();
jenkinsCrawlerDTO.setJobUrl(jobUrl);
}
#After
public void cleanup() {
super.tearDown();
}
#Test
public void testAbortedJobAddedSuccessfullyToExcludedRun() {
int countBeforeImport = ExcludedJenkinsRuns.count();
jenkinsJobService.handleTestResults(jobUrl,JUNIT_TEST_PARAMETERS);
int countAfterImport = ExcludedJenkinsRuns.count();
Assert.assertEquals(countBeforeImport+1, countAfterImport);
ExcludedJenkinsRuns excludedRun = ExcludedJenkinsRuns.findByJobNameLike(jenkinsCrawlerDTO.jobName);
Assert.assertNotNull(excludedRun);
Assert.assertEquals(jobUrl, excludedRun.jobUrl);
Assert.assertEquals(jenkinsCrawlerDTO.jobName, excludedRun.jobName);
Assert.assertEquals(jenkinsCrawlerDTO.jenkinsServer, excludedRun.jenkinsServer);
Assert.assertEquals(jenkinsCrawlerDTO.buildNumber.toInteger(), excludedRun.buildNumber);
Assert.assertEquals("Build Aborted", excludedRun.exclusionReason);
}
}
*/
I cant figure out the issue in this code. Can anyone help me?
While executing this test case, following error I'm facing...
Please anyone suggests me in overcoming this issue.
It means that you try to put a LinkedHashMap in constructor of Product Model but there is no constructor with LinkedHashMap parameter.
I guess the problem is your Unit Test. The Model constructor will be added by grails framework. You aren`t running grails framework in your Unit Test, because you use GroovyTestCase instead of Spock.
Lock here https://grails.github.io/grails-doc/3.0.5/guide/single.html#unitTesting

Why Cassandra throwing com.datastax.driver.core.exceptions.InvalidQueryException: Multiple definitions found for column

Context:
I am running a jUnit test in eclipse by using embedded Cassandra to test my DAO class which is using an Astyanax client configured for JavaDriver. When DAO object instance insert into Cassandra I am getting this exception com.datastax.driver.core.exceptions.InvalidQueryException: Multiple definitions found for column ..columnname
TestClass
public class LeaderBoardDaoTest {
private static LeaderBoardDao dao;
public static CassandraCQLUnit cassandraCQLUnit;
private String hostIp = "127.0.0.1";
private int port = 9142;
public Session session;
public Cluster cluster;
#BeforeClass
public static void startCassandra() throws IOException, TTransportException, ConfigurationException, InterruptedException {
System.setProperty("archaius.deployment.applicationId", "leaderboardapi");
System.setProperty("archaius.deployment.environment", "test");
EmbeddedCassandraServerHelper.startEmbeddedCassandra("cassandra.yaml");
// cassandraCQLUnit = new CassandraCQLUnit(new
// ClassPathCQLDataSet("simple.cql", "lbapi"), "cassandra.yaml");
Injector injector = Guice.createInjector(new TestModule());
dao = injector.getInstance(LeaderBoardDao.class);
}
#Before
public void load() {
cluster = new Cluster.Builder().withClusterName("leaderboardcassandra").addContactPoints(hostIp).withPort(port).build();
session = cluster.connect();
CQLDataLoader dataLoader = new CQLDataLoader(session);
dataLoader.load(new ClassPathCQLDataSet("simple.cql", "lbapi"));
session = dataLoader.getSession();
}
#Test
public void test() {
ResultSet result = session.execute("select * from mytable WHERE id='myKey01'");
Assert.assertEquals(result.iterator().next().getString("value"), "myValue01");
}
#Test
public void testInsert() {
LeaderBoard lb = new LeaderBoard();
lb.setName("name-1");
lb.setDescription("description-1");
lb.setActivityType(ActivityType.FUEL);
lb.setImage("http:/");
lb.setLbId(UUID.fromString("3F2504E0-4F89-41D3-9A0C-0305E82C3301"));
lb.setStartTime(new Date());
lb.setEndTime(new Date());
dao.insert(lb);
ResultSet resultSet = session.execute("select * from leaderboards WHERE leaderboardid='3F2504E0-4F89-41D3-9A0C-0305E82C3301'");
}
#After
public void clearCassandra() {
EmbeddedCassandraServerHelper.cleanEmbeddedCassandra();
}
#AfterClass
public static void stopCassandra() {
EmbeddedCassandraServerHelper.stopEmbeddedCassandra();
}
}
Class under test
#Singleton
public class LeaderBoardDao {
private static final Logger log = LoggerFactory.getLogger(LeaderBoardDao.class);
#Inject
private AstyanaxMutationsJavaDriverClient client;
private static final String END_TIME = "end_time";
private static final String START_TIME = "start_time";
private static final String IMAGE = "image";
private static final String ACTIVITY_TYPE = "activity_type";
private static final String DESCRIPTION = "description";
private static final String NAME = "name";
private static final String LEADERBOARD_ID = "leaderboardID";
private static final String COLUMN_FAMILY_NAME = "leaderboards";
private ColumnFamily<UUID, String> cf;
public LeaderBoardDao() throws ConnectionException {
cf = ColumnFamily.newColumnFamily(COLUMN_FAMILY_NAME, UUIDSerializer.get(), StringSerializer.get());
}
/**
* Writes the Leaderboard to the database.
*
* #param lb
*/
public void insert(LeaderBoard lb) {
try {
MutationBatch m = client.getKeyspace().prepareMutationBatch();
cf.describe(client.getKeyspace());
m.withRow(cf, lb.getLbId()).putColumn(LEADERBOARD_ID, UUIDUtil.asByteArray(lb.getLbId()), null).putColumn(NAME, lb.getName(), null).putColumn(DESCRIPTION, lb.getDescription(), null)
.putColumn(ACTIVITY_TYPE, lb.getActivityType().name(), null).putColumn(IMAGE, lb.getImage()).putColumn(START_TIME, lb.getStartTime()).putColumn(END_TIME, lb.getEndTime());
m.execute();
} catch (ConnectionException e) {
Throwables.propagate(e);
}
}
/**
* Reads leaderboard from database
*
* #param id
* #return {#link LeaderBoard}
*/
public LeaderBoard read(UUID id) {
OperationResult<ColumnList<String>> result;
LeaderBoard lb = null;
try {
result = client.getKeyspace().prepareQuery(cf).getKey(id).execute();
ColumnList<String> cols = result.getResult();
if (!cols.isEmpty()) {
lb = new LeaderBoard();
lb.setLbId(cols.getUUIDValue(LEADERBOARD_ID, null));
lb.setName(cols.getStringValue(NAME, null));
lb.setActivityType(ActivityType.valueOf(cols.getStringValue(ACTIVITY_TYPE, null)));
lb.setDescription(cols.getStringValue(DESCRIPTION, null));
lb.setEndTime(cols.getDateValue(END_TIME, null));
lb.setStartTime(cols.getDateValue(START_TIME, null));
lb.setImage(cols.getStringValue(IMAGE, null));
} else {
log.warn("read: is empty: no record found for " + id);
}
return lb;
} catch (ConnectionException e) {
log.error("failed to read from C*", e);
throw new RuntimeException("failed to read from C*", e);
}
}
}
When the Java driver throws an InvalidQueryException, it's rethrowing an error from Cassandra. The error "Multiple definitions found for column..." indicates that a column is mentioned more than once in an update statement. You can simulate it in cqlsh:
cqlsh> create table test(i int primary key);
cqlsh> insert into test (i, i) values (1, 2);
code=2200 [Invalid query] message="Multiple definitions found for column i"
I'm not familiar with Astyanax, but my guess is that it already adds the id to the query when you call withRow, so you don't need to add it again with putColumn. Try removing that call (second line in reformatted sample below):
m.withRow(cf, lb.getLbId())
.putColumn(LEADERBOARD_ID, UUIDUtil.asByteArray(lb.getLbId()), null)
... // other putColumn calls

J2me synchronization of methods

I initializing a variable in my startApp method and after I do so I call a thread to check the whole run time of the app what is the current screen (canvas) and activating it's thread
import java.io.IOException;
import java.io.InputStream;
import zuma.core.MyGameCanvas;
import zuma.core.Game;
import zuma.gui.LevelSelectionMenu;
import zuma.gui.MainMenu;
import javax.microedition.lcdui.Display;
import javax.microedition.media.Manager;
import javax.microedition.media.MediaException;
import javax.microedition.midlet.*;
import zuma.util.AudioManager;
public class Midlet extends MIDlet implements Runnable{
private static Display display;
private static Game game;
private static MainMenu mainMenu;
private static LevelSelectionMenu levelSelectionMenu;
private static MyGameCanvas myGameCanvas;
private Thread t;
/**
* Specifies what happens when starting the application.
*/
public void startApp() {
display = Display.getDisplay(this);
display.setCurrent(getMainMenu());
t = new Thread(this);
t.start();
}
/**
* Specifies what happens when pausing the application.
*/
public void pauseApp() {
}
/**
* Specifies what happens when exiting the application.
* #param unconditional
*/
public void destroyApp(boolean unconditional) {
//game.getLevelsRecordStore().closeRecordStore();
notifyDestroyed();
}
/**
*
* #return the display.
*/
public static Display getDisplay() {
return display;
}
/**
*
* #return the game.
*/
public static Game getGame() {
if (game == null) { //|| game.getLevels() == null) {
game = new Game();
}
return game;
}
/**
*
* #return the mainMenu.
*/
public static synchronized MainMenu getMainMenu() {
if (mainMenu == null) {
mainMenu = new MainMenu();
}
return mainMenu;
}
/**
*
* #return the levelSelectionMenu.
*/
public static LevelSelectionMenu getLevelSelectionMenu() {
if (levelSelectionMenu == null) {
levelSelectionMenu = new LevelSelectionMenu(getGame());
}
return levelSelectionMenu;
}
/**
*
* #return the myGameCanvas.
*/
public static MyGameCanvas getMyGameCanvas() {
if (myGameCanvas == null) {
myGameCanvas = new MyGameCanvas();
}
return myGameCanvas;
}
/**
* Starts the thread of the current display.
*/
public synchronized void run() {
while (true) {
if (display.getCurrent().equals(mainMenu)) {
if (mainMenu.getT() == null || !mainMenu.getT().isAlive()) {
mainMenu.init();
}
if (getMainMenu().isQuitRequest()) {
destroyApp(true);
}
}
else if (display.getCurrent().equals(levelSelectionMenu)) {
if (levelSelectionMenu.getT() == null || !levelSelectionMenu.getT().isAlive()) {
levelSelectionMenu.init();
}
}
else if (display.getCurrent().equals(myGameCanvas)) {
if (myGameCanvas.getT() == null || !myGameCanvas.getT().isAlive()) {
myGameCanvas.init(game.getLevels()[game.getChosenLevel()]);
}
}
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
Now as you can see I first init the variable mainMenu in this line
display.setCurrent(getMainMenu());
and only then call run method, but somehow SOMETIMES it gives me null pointer exception on this line
if (display.getCurrent().equals(mainMenu))
so somehow the thread is getting called even before the mainMenu is being created and I have no idea how, what I tried is making the run method and the getMainMenu methos synchronized but it didnt work, can anyone help me ?
The thread is not getting called before the main menu is created. After setCurrent is called, there is actually a delay before the displayable is made visible. The doc says: "The setCurrent() method returns immediately, without waiting for the change to take place. Because of this delay, a call to getCurrent() shortly after a call to setCurrent() is unlikely to return the value passed to setCurrent()."

How can I implement a multithreaded PostProcessor in ActivePivot?

I consider an ActivePivot instance to compute CVA (Credit Valuation Adjustment).
I have to apply a piece of logic on a large number of cells (20k for each counter-party), each being associated to a float array of size 10k. Even if ActivePivot is massively multithreaded, an ABasicPostProcessor will be applied in a mono-threaded way for each range location. How could I make it compute through my point location in a multi-threaded way?
I built the following class, which specialize ABasicPostProcessor (a Core class enabling fast implementation of per-point post-processor) by just adding the calls to doEvaluation in a multi-threaded way.
Given an ABasicPostProcessor specialisation, one simply has to extend AParallelBasicPostProcessor in order to gain parallel evaluation!
/**
* Specialization of ABasicPostProcessor which will call doEvaluation in a
* multithreaded way
*
* #author BLA
*/
public abstract class AParallelBasicPostProcessor<OutputType> extends ABasicPostProcessor<OutputType> {
private static final long serialVersionUID = -3453966549173516186L;
public AParallelBasicPostProcessor(String name, IActivePivot pivot) {
super(name, pivot);
}
#Override
public void evaluate(ILocation location, final IAggregatesRetriever retriever) throws QuartetException {
// Retrieve required aggregates
final ICellSet cellSet = retriever.retrieveAggregates(Collections.singleton(location), Arrays.asList(prefetchMeasures));
// Prepare a List
List<ALocatedRecursiveTask<OutputType>> tasks = new ArrayList<ALocatedRecursiveTask<OutputType>>();
// Create the procedure to hold the parallel sub-tasks
final ICellsProcedure subTasksGeneration = makeSubTasksGenerationProcedure(tasks);
cellSet.forEachLocation(subTasksGeneration, underlyingMeasures);
ForkJoinTask.invokeAll(tasks);
for (ALocatedRecursiveTask<OutputType> task : tasks) {
OutputType returnValue;
try {
returnValue = task.get();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
// re-throw the root cause of the ExecutionException
throw new RuntimeException(e.getCause());
}
// We can write only non-null aggregates
if (null != returnValue) {
writeInRetriever(retriever, task.getLocation(), returnValue);
}
}
}
protected void writeInRetriever(IAggregatesRetriever retriever, ILocation location, OutputType returnValue) {
retriever.write(location, returnValue);
}
protected ICellsProcedure makeSubTasksGenerationProcedure(List<ALocatedRecursiveTask<OutputType>> futures) {
return new SubTasksGenerationProcedure(futures);
}
/**
* {#link ICellsProcedure} registering a {#link ALocatedRecursiveTask} per
* point location
*/
protected class SubTasksGenerationProcedure implements ICellsProcedure {
protected List<ALocatedRecursiveTask<OutputType>> futures;
public SubTasksGenerationProcedure(List<ALocatedRecursiveTask<OutputType>> futures) {
this.futures = futures;
}
#Override
public boolean execute(final ILocation pointLocation, int rowId, Object[] measures) {
// clone the array of measures as it is internally used as a buffer
final Object[] clone = measures.clone();
futures.add(makeLocatedFuture(pointLocation, clone));
return true;
}
}
protected ALocatedRecursiveTask<OutputType> makeLocatedFuture(ILocation pointLocation, Object[] measures) {
return new LocatedRecursiveTask(pointLocation, measures);
}
/**
* A specialization of RecursiveTask by associating it to a
* {#link ILocation}
*
* #author BLA
*
*/
protected static abstract class ALocatedRecursiveTask<T> extends RecursiveTask<T> {
private static final long serialVersionUID = -6014943980790547011L;
public abstract ILocation getLocation();
}
/**
* Default implementation of {#link ALocatedRecursiveTask}
*
* #author BLA
*
*/
protected class LocatedRecursiveTask extends ALocatedRecursiveTask<OutputType> {
private static final long serialVersionUID = 676859831679236794L;
protected ILocation pointLocation;
protected Object[] measures;
public LocatedRecursiveTask(ILocation pointLocation, Object[] measures) {
this.pointLocation = pointLocation;
this.measures = measures;
if (pointLocation.isRange()) {
throw new RuntimeException(this.getClass() + " accepts only point location: " + pointLocation);
}
}
#Override
protected OutputType compute() {
try {
// The custom evaluation will be computed in parallel
return AParallelBasicPostProcessor.this.doEvaluation(pointLocation, measures);
} catch (QuartetException e) {
throw new RuntimeException(e);
}
}
#Override
public ILocation getLocation() {
return pointLocation;
}
}
}
The ActivePivot query engine is heavily multithreaded, the invocation of several post processors within a single query is done in parallel (unless one depends on the result of another of course). When the same post processor is executed several times over the locations involved in the query, that's also done in parallel. So before rolling up your sleeves, it is worth checking whether there isn't a more obvious bottleneck in your query plan.
Now the invocation of one post processor over one location is indeed an indivisible workload in the ActivePivot query engine. And in the case aggregates are not just numbers that sum in nanoseconds, but large or structured objects like vectors, there may be room for parallelism driven performance boost.
The ActivePivot query engine is built on top of a fork/join pool (http://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html). It means that your post processor code is always called from within the fork join pool, and that makes it possible to fork your own sub-tasks, then join them. That is considered an expert trick, don't try that without a fair understanding of how the fork join pool works.
Let's consider a post processor that for each evaluated location computes the maximum of several measures:
package com.quartetfs.pivot.sandbox.postprocessor.impl;
import com.quartetfs.biz.pivot.IActivePivot;
import com.quartetfs.biz.pivot.ILocation;
import com.quartetfs.biz.pivot.postprocessing.impl.ABasicPostProcessor;
import com.quartetfs.fwk.QuartetException;
import com.quartetfs.fwk.QuartetExtendedPluginValue;
/**
*
* Post processor that computes the MAX of several measures.
*
* #author Quartet FS
*
*/
#QuartetExtendedPluginValue(interfaceName = "com.quartetfs.biz.pivot.postprocessing.IPostProcessor", key = MaxPostProcessor.TYPE)
public class MaxPostProcessor extends ABasicPostProcessor<Double> {
/** serialVersionUID */
private static final long serialVersionUID = -8886545079342151420L;
/** Plugin type */
public static final String TYPE = "MAX";
public MaxPostProcessor(String name, IActivePivot pivot) {
super(name, pivot);
}
#Override
public String getType() { return TYPE; }
#Override
protected Double doEvaluation(ILocation location, Object[] measures) throws QuartetException {
double max = ((Number) measures[0]).doubleValue();
for(int i = 1; i < measures.length; i++) {
max = Math.max(max, ((Number) measures[i]).doubleValue());
}
return max;
}
}
In that post processor the leaf locations resulting from the evaluated range location will be computed one after the other. You can decide to create tasks instead, and execute those tasks in parallel through the fork join pool. I hope the following will get you started:
package com.quartetfs.pivot.sandbox.postprocessor.impl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import jsr166y.ForkJoinTask;
import jsr166y.RecursiveTask;
import com.quartetfs.biz.pivot.IActivePivot;
import com.quartetfs.biz.pivot.ILocation;
import com.quartetfs.biz.pivot.cellset.ICellSet;
import com.quartetfs.biz.pivot.cellset.ICellsProcedure;
import com.quartetfs.biz.pivot.query.aggregates.IAggregatesRetriever;
import com.quartetfs.fwk.QuartetException;
import com.quartetfs.fwk.QuartetExtendedPluginValue;
/**
*
* Post processor that computes the MAX of several measures,
* evaluation of locations is performed in parallel.
*
* #author Quartet FS
*
*/
#QuartetExtendedPluginValue(interfaceName = "com.quartetfs.biz.pivot.postprocessing.IPostProcessor", key = ParallelMaxPostProcessor.TYPE)
public class ParallelMaxPostProcessor extends MaxPostProcessor {
/** serialVersionUID */
private static final long serialVersionUID = -8886545079342151420L;
/** Plugin type */
public static final String TYPE = "PMAX";
public ParallelMaxPostProcessor(String name, IActivePivot pivot) {
super(name, pivot);
}
#Override
public String getType() { return TYPE; }
#Override
public void evaluate(ILocation location, IAggregatesRetriever retriever)throws QuartetException {
try {
// Retrieve required aggregates
ICellSet cellSet = retriever.retrieveAggregates(Collections.singleton(location), Arrays.asList(prefetchMeasures));
// Evaluate the cell set to create tasks
ParallelEvaluationProcedure evalProcedure = new ParallelEvaluationProcedure();
cellSet.forEachLocation(evalProcedure);
// Execute the tasks in parallel and write results
evalProcedure.writeResults(retriever);
} catch(Exception e) {
throw new QuartetException("Evaluation of " + this + " on location " + location + " failed.", e);
}
}
/**
* Procedure evaluated on the cell set.
*/
protected class ParallelEvaluationProcedure implements ICellsProcedure {
/** List of tasks */
protected final List<MaxComputation> tasks = new ArrayList<ParallelMaxPostProcessor.MaxComputation>();
#Override
public boolean execute(ILocation location, int rowId, Object[] measures) {
Object[] numbers = measures.clone();
tasks.add(new MaxComputation(location, numbers));
return true; // continue
}
/** Once all the tasks are executed, write results */
public void writeResults(IAggregatesRetriever retriever) throws Exception {
// Invoke all the tasks in parallel
// using the fork join pool that runs the post processor.
ForkJoinTask.invokeAll(tasks);
for(MaxComputation task : tasks) {
retriever.write(task.location, task.get());
}
}
}
/**
* Max computation task. It illustrates our example well
* but in real-life this would be too little
* of a workload to deserve parallel execution.
*/
protected class MaxComputation extends RecursiveTask<Double> {
/** serialVersionUID */
private static final long serialVersionUID = -5843737025175189495L;
final ILocation location;
final Object[] numbers;
public MaxComputation(ILocation location, Object[] numbers) {
this.location = location;
this.numbers = numbers;
}
#Override
protected Double compute() {
try {
return doEvaluation(location, numbers);
} catch (QuartetException e) {
completeExceptionally(e);
return null;
}
}
}
}

Accessing secure restful web services using jersey client

I have created web services based on Jersey (auto generated via Netbeans).
I have also created a user names “testClient” with password “secret” and created User group “Users” and used file Realm using glassfish 3.0.1 admin console.
I have also mapped web.xml and sun-web.xml accordingly.
My web services are secured successfully; as I access the web site I receive a security warning and then I am prompt to give username and password to access any content of the website. It is working fine when accessed via web browser.
Now I have written a simple client based on jersey and tried to access the web services offered by the 1st project; the client code is here
Auto generated Jersey client code
public class JerseyClient {
private WebResource webResource;
private Client client;
private static final String BASE_URI = "https://localhost:9028/testsecurity2/resources";
public JerseyClient() {
com.sun.jersey.api.client.config.ClientConfig config = new com.sun.jersey.api.client.config.DefaultClientConfig(); // SSL configuration
// SSL configuration
config.getProperties().put(com.sun.jersey.client.urlconnection.HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new com.sun.jersey.client.urlconnection.HTTPSProperties(getHostnameVerifier(), getSSLContext()));
client = Client.create(config);
webResource = client.resource(BASE_URI).path("manufacturers");
}
public <T> T get_XML(Class<T> responseType) throws UniformInterfaceException {
return webResource.accept(javax.ws.rs.core.MediaType.APPLICATION_XML).get(responseType);
}
public <T> T get_JSON(Class<T> responseType) throws UniformInterfaceException {
return webResource.accept(javax.ws.rs.core.MediaType.APPLICATION_JSON).get(responseType);
}
public void close() {
client.destroy();
}
public void setUsernamePassword(String username, String password) {
client.addFilter(new com.sun.jersey.api.client.filter.HTTPBasicAuthFilter(username, password));
}
private HostnameVerifier getHostnameVerifier() {
return new HostnameVerifier() {
#Override
public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
return true;
}
};
}
private SSLContext getSSLContext() {
javax.net.ssl.TrustManager x509 = new javax.net.ssl.X509TrustManager() {
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] arg0, String arg1) throws java.security.cert.CertificateException {
return;
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] arg0, String arg1) throws java.security.cert.CertificateException {
return;
}
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
SSLContext ctx = null;
try {
ctx = SSLContext.getInstance("SSL");
ctx.init(null, new javax.net.ssl.TrustManager[]{x509}, null);
} catch (java.security.GeneralSecurityException ex) {
}
return ctx;
}
}
Code in Main Method; uses auto generated code
JerseyClient client = new JerseyClient();
client.setUsernamePassword("testClient", "secret");
Object response = client.get_XML(String.class);
// do whatever with response
client.close();
Results:
Exception in thread "main" com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:128)
at com.sun.jersey.api.client.filter.HTTPBasicAuthFilter.handle(HTTPBasicAuthFilter.java:78)
at com.sun.jersey.api.client.Client.handle(Client.java:457)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:557)
at com.sun.jersey.api.client.WebResource.access$300(WebResource.java:69)
at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:451)
at clients.JerseyClient.get_XML(JerseyClient.java:23)
at clients.NewMain1.main(NewMain1.java:20)
Caused by: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:808)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1112)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1139)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1123)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1049)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:373)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:318)
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler._invoke(URLConnectionClientHandler.java:215)
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:126)
... 7 more
Caused by: java.io.EOFException: SSL peer shut down incorrectly
at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:333)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:789)
... 17 more
Java Result: 1
I also want to inform that these are two different projects running on different servers both are glassfish 3.0.1. I also tried to run client and services on the same server but all in vain. I am stuck; kindly help me.
Cheers!
i have found a good resource regarding my problem. Here it is
http://wiki.open-esb.java.net/attach/RestBCEchoSSL/SslClient.java
I made few changes in my code regarding the given source and it worked perfectly. Actually I was not passing the certificate and key stores properly.
Here is the full code.
package clients;
import com.sun.jersey.api.client.*;
import javax.net.ssl.*;
import java.io.*;
import java.net.Socket;
import java.security.*;
import javax.ws.rs.core.UriBuilder;
import com.sun.jersey.client.urlconnection.HTTPSProperties;
public class JerseyClient {
private WebResource webResource;
private Client client;
//private static final String BASE_URI = "https://localhost:9028/testsecurity2/resources";
private static final String truststore_path = "D:/Practice Apps/glassfish-3.0.1 Stand Alone/glassfish/domains/domain2/config/cacerts.jks";
private static final String truststore_password = "changeit";
private static final String keystore_path = "D:/Practice Apps/glassfish-3.0.1 Stand Alone/glassfish/domains/domain2/config/keystore.jks";
private static final String keystore_password = "changeit";
private static final String url = "https://localhost:9029/testsecurity2/resources/manufacturers/";
public JerseyClient() {
com.sun.jersey.api.client.config.ClientConfig config = new com.sun.jersey.api.client.config.DefaultClientConfig(); // SSL configuration
// SSL configuration
config.getProperties().put(com.sun.jersey.client.urlconnection.HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new com.sun.jersey.client.urlconnection.HTTPSProperties(getHostnameVerifier(), getSSLContext()));
client = Client.create(config);
webResource = client.resource(url);
}
public <T> T get_XML(Class<T> responseType) throws UniformInterfaceException {
return webResource.accept(javax.ws.rs.core.MediaType.APPLICATION_XML).get(responseType);
}
public <T> T get_JSON(Class<T> responseType) throws UniformInterfaceException {
return webResource.accept(javax.ws.rs.core.MediaType.APPLICATION_JSON).get(responseType);
}
public void close() {
client.destroy();
}
public void setUsernamePassword(String username, String password) {
client.addFilter(new com.sun.jersey.api.client.filter.HTTPBasicAuthFilter(username, password));
}
private HostnameVerifier getHostnameVerifier() {
return new HostnameVerifier() {
#Override
public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
return true;
}
};
}
private SSLContext getSSLContext() {
TrustManager mytm[] = null;
KeyManager mykm[] = null;
try {
mytm = new TrustManager[]{new MyX509TrustManager(truststore_path, truststore_password.toCharArray())};
mykm = new KeyManager[]{new MyX509KeyManager(keystore_path, keystore_password.toCharArray())};
} catch (Exception ex) {
ex.printStackTrace();
}
SSLContext ctx = null;
try {
ctx = SSLContext.getInstance("SSL");
ctx.init(mykm, mytm, null);
} catch (java.security.GeneralSecurityException ex) {
}
return ctx;
}
/**
* Taken from http://java.sun.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html
*
*/
static class MyX509TrustManager implements X509TrustManager {
/*
* The default PKIX X509TrustManager9. We'll delegate
* decisions to it, and fall back to the logic in this class if the
* default X509TrustManager doesn't trust it.
*/
X509TrustManager pkixTrustManager;
MyX509TrustManager(String trustStore, char[] password) throws Exception {
this(new File(trustStore), password);
}
MyX509TrustManager(File trustStore, char[] password) throws Exception {
// create a "default" JSSE X509TrustManager.
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(trustStore), password);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(ks);
TrustManager tms[] = tmf.getTrustManagers();
/*
* Iterate over the returned trustmanagers, look
* for an instance of X509TrustManager. If found,
* use that as our "default" trust manager.
*/
for (int i = 0; i < tms.length; i++) {
if (tms[i] instanceof X509TrustManager) {
pkixTrustManager = (X509TrustManager) tms[i];
return;
}
}
/*
* Find some other way to initialize, or else we have to fail the
* constructor.
*/
throw new Exception("Couldn't initialize");
}
/*
* Delegate to the default trust manager.
*/
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
pkixTrustManager.checkClientTrusted(chain, authType);
} catch (CertificateException excep) {
// do any special handling here, or rethrow exception.
}
}
/*
* Delegate to the default trust manager.
*/
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
pkixTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException excep) {
/*
* Possibly pop up a dialog box asking whether to trust the
* cert chain.
*/
}
}
/*
* Merely pass this through.
*/
public X509Certificate[] getAcceptedIssuers() {
return pkixTrustManager.getAcceptedIssuers();
}
}
/**
* Inspired from http://java.sun.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html
*
*/
static class MyX509KeyManager implements X509KeyManager {
/*
* The default PKIX X509KeyManager. We'll delegate
* decisions to it, and fall back to the logic in this class if the
* default X509KeyManager doesn't trust it.
*/
X509KeyManager pkixKeyManager;
MyX509KeyManager(String keyStore, char[] password) throws Exception {
this(new File(keyStore), password);
}
MyX509KeyManager(File keyStore, char[] password) throws Exception {
// create a "default" JSSE X509KeyManager.
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(keyStore), password);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509", "SunJSSE");
kmf.init(ks, password);
KeyManager kms[] = kmf.getKeyManagers();
/*
* Iterate over the returned keymanagers, look
* for an instance of X509KeyManager. If found,
* use that as our "default" key manager.
*/
for (int i = 0; i < kms.length; i++) {
if (kms[i] instanceof X509KeyManager) {
pkixKeyManager = (X509KeyManager) kms[i];
return;
}
}
/*
* Find some other way to initialize, or else we have to fail the
* constructor.
*/
throw new Exception("Couldn't initialize");
}
public PrivateKey getPrivateKey(String arg0) {
return pkixKeyManager.getPrivateKey(arg0);
}
public X509Certificate[] getCertificateChain(String arg0) {
return pkixKeyManager.getCertificateChain(arg0);
}
public String[] getClientAliases(String arg0, Principal[] arg1) {
return pkixKeyManager.getClientAliases(arg0, arg1);
}
public String chooseClientAlias(String[] arg0, Principal[] arg1, Socket arg2) {
return pkixKeyManager.chooseClientAlias(arg0, arg1, arg2);
}
public String[] getServerAliases(String arg0, Principal[] arg1) {
return pkixKeyManager.getServerAliases(arg0, arg1);
}
public String chooseServerAlias(String arg0, Principal[] arg1, Socket arg2) {
return pkixKeyManager.chooseServerAlias(arg0, arg1, arg2);
}
}
}
and code to run the client in main class
public static void main(String[] args) {
JerseyClient client = new JerseyClient();
client.setUsernamePassword("testClient", "secret");
Object response = client.get_XML(String.class);
System.out.println(response);
// do whatever with response
client.close();
}

Resources