Archive

Posts Tagged ‘java’

Is your code thread safe?

The last weeks I started to considerate about concurrency testing. I wrote an utility that tries to test if your code is thread safe or not.

When you repeat an experiment many times, the result tends to be the expected

This means that if you throw a die one time, we can not know what result is going to happen, but if we do it thousands of times, we will know that each result is going to happens 1/6 of the times.

In less words, lets repeat this many times at the same time and then check if it is fine or not. The problem here is, how to do it at the same time?.

The utility has 2 classes, ConcurrenceHelper and Task. Task is an interface that you need to implement to provide ConcurrenceHelper the job to do. ConcurrenceHelper will trigger all the tasks “at the same time”.

This is the interface:

public interface Task {

	void execute();
	
}

And this class will trigger all the tasks in different threads. Onces all the threads have executed the tasks, the main thread will leave the method (it means that this method is synchronous).

import java.util.concurrent.CountDownLatch;

public class ConcurrenceHelper {

	public void triggerTasks(final int nThreadsPerTask, final Task ... tasks) throws InterruptedException{
		final CountDownLatch waitForThreadsEnd = new CountDownLatch(nThreadsPerTask*tasks.length);
		final CountDownLatch waitToStart = new CountDownLatch(nThreadsPerTask*tasks.length);
		for(final Task task : tasks){
			for(int i=0;i<nThreadsPerTask;i++){
				final String THREAD_NAME = task+"-"+i;
				new Thread(new Runnable() {
					@Override
					public void run() {
						try {
							waitToStart.countDown();
							// Threads are waiting until countDown=nThreadsPerTask*tasks.length
							waitToStart.await();
							task.execute();
						} catch (InterruptedException e) {
							throw new RuntimeException(THREAD_NAME+" can not wait any more o_O", e);
						}finally{
                        	waitForThreadsEnd.countDown();
                        }
						
					}
				}, THREAD_NAME).start();
			}
		}
		// The main thread is waiting until countDown=nThreadsPerTask*tasks.length
		waitForThreadsEnd.await();
		// At this point all threads have executed the task
	}
	
}

And now lets do some testing:


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;

import java.util.List;
import java.util.Vector;

import org.junit.Test;

public class SamplesTest {

	private final ConcurrenceHelper concurrence = new ConcurrenceHelper();
	private final int CONCURRENCE_TASKS = 10000;
	
	@Test
	public void vectorIsThreadSafe() throws InterruptedException{
		final List<Long> list = new Vector<>();
		concurrence.triggerTasks(CONCURRENCE_TASKS, new Task() {
			@Override
			public void execute() {
				list.add(System.currentTimeMillis());
			}
		});
		System.out.println("Value "+list.size());
		assertEquals(CONCURRENCE_TASKS, list.size());
	}
	
	@Test
	public void notThreadSafeClass() throws InterruptedException{
		final NotThreadSafeClass obj = new NotThreadSafeClass();
		concurrence.triggerTasks(CONCURRENCE_TASKS, new Task() {	
			@Override
			public void execute() {
				obj.i++;
			}
		});
		System.out.println("Value "+obj.i);
		assertNotEquals(CONCURRENCE_TASKS, obj.i);
	}
	
	private class NotThreadSafeClass{
		protected int i;
	}
	
}

We are testing one class that we know that is thread safe (Vector) and other one that is not thread safe (NotThreadSafeClass). It is easier to test that one class is thread safe than checking that is not thread safe. The test vectorIsThreadSafe() will be successfull the 100% of the times, but notThreadSafeClass() will not be successfull the 100%. For that reason, to prevent you to have randomly testing errors, make the testing oriented to check that is thread safe (by the way, is what we really want to test).

To prevent concurrency problems, try to make the classes as much inmutables as possible.

Advertisements

Creating an object stream from a JDBC ResultSet

08/14/2014 6 comments

The introduction of  features Stream API and Lambda in Java 8 enables us to make an elegant conversion from a JDBC ResultSet to a stream of objects just providing a mapping function. Such function could be, of course, a lambda.

Basically, the idea is to generate a Stream using a ResultSet as Supplier:

public class ResultSetSupplier implements Supplier<T>{

		private final ResultSet rs;
		private final Function<ResultSet, T> mappingFunction;

		private ResultSetSupplier(ResultSet rs,
                    Function<ResultSet, T> mappingFunction) {
			this.rs = rs;
			this.mappingFunction = mappingFunction;
		}

		@Override
		public T get() {
			try {
				if (rs.next())
					return mappingFunction.apply(rs);
			} catch (SQLException e) {
				e.printStackTrace();
			}
			return null;
		}
	}

Parameter mappingFunction, which might be a lambda expression, is used to build T instances from a ResultSet. Just like ActiveRecord pattern, every row in such ResultSet maps to an instance of T, where columns are attributes of T.

Let’s consider class City:

public class City{
		String city;
		String country;
		public City(String city, String country) {
			this.city = city;
			this.country = country;
		}
		public String getCountry() {
			return country;
		}
		@Override
		public String toString() {
			return "City [city=" + city + ", country=" + country + ";]";
		}
		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + ((city == null) ? 0 : city.hashCode());
			result = prime * result
					+ ((country == null) ? 0 : country.hashCode());
			return result;
		}
		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			City other = (City) obj;
			if (city == null) {
				if (other.city != null)
					return false;
			} else if (!city.equals(other.city))
				return false;
			if (country == null) {
				if (other.country != null)
					return false;
			} else if (!country.equals(other.country))
				return false;
			return true;
		}
	}

The mapping function for City objects could be a lambda expression like the following:

(ResultSet rs) -> {
                try
                {
                  return new City(rs.getString("city"), rs.getString("country"));
		} catch (Exception e) {
		  return null;
		}}

We have assumed database columns are called city and country, respectively.

Although both PreparedStatement and ResultSet implement AutoCloseable interface, as a  resultSet must be provided to create the object stream, it does make sense to close such resultSet when the stream is closed as well.

A possible approach could be to use a proxy to intercept method invocation on the object stream. Thus, as close() method is invoked on the proxy, it will invoke close() on the provided resultSet. All method invocations will be invoked on the object stream as well, in order to be able to provide all Stream features. That is easy to achieve using a proxy.

Let’s have a look. We will have a proxy factory and a invocation handler:

public class ResultSetStreamInvocationHandler<T> implements InvocationHandler{

  private Stream<T> stream; // proxy will intercept method calls to such stream
  private PreparedStatement st;
  private ResultSet rs;

  public void setup(PreparedStatement st, Function<ResultSet, T> mappingFunction)
  throws SQLException{
    // PreparedStatement must be already setup in order
    // to just call executeQuery()
    this.st = st;
    rs = st.executeQuery();
    stream = Stream.generate(new ResultSetSupplier(rs, mappingFunction));
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args)
  throws Throwable {

    if (method == null)
      throw new RuntimeException("null method null");

    // implement AutoCloseable for PreparedStatement
    // as calling close() more than once has no effects
    if (method.getName().equals("close") && args == null){
    // invoked close(), no arguments
      if (st != null){
        st.close(); // closes ResultSet too
      }
    }

    return method.invoke(stream, args);
  }

private class ResultSetSupplier implements Supplier<T>{

  private final ResultSet rs;
  private final Function<ResultSet, T> mappingFunction;

  private ResultSetSupplier(ResultSet rs, Function<ResultSet, T> mappingFunction) {
    this.rs = rs;
    this.mappingFunction = mappingFunction;
  }

  @Override
  public T get() {
    try {
      if (rs.next())
        return mappingFunction.apply(rs);
    } catch (SQLException e) {
     e.printStackTrace();
    }
    return null;
  }
}

}

Please note how invoke is used to intercept method calls. In case close() is called, close() is called on PreparedStatement as well. For every method called, the corresponding method call is invoked in the stream being proxied.

And the factory:

 

public class ResultSetStream<T>{

	@SuppressWarnings("unchecked")
	public Stream<T> getStream(PreparedStatement st,
            Function<ResultSet, T> mappingFunction) throws SQLException{
		final ResultSetStreamInvocationHandler<T> handler =
                    new ResultSetStreamInvocationHandler<T>();
		handler.setup(st, mappingFunction);
		Stream<T> proxy = (Stream<T>) Proxy.newProxyInstance(getClass().getClassLoader(),
                new Class<?>[] {Stream.class},
                handler);
		return proxy;
	}
}

To put it all together, let’s write a simple test to show usage. Mockito will be used to mock both PreparedStatement and ResultSet to avoid running tests against a real database.


public class ResultSetStreamTest {

	private class City{
		String city;
		String country;
		public City(String city, String country) {
			this.city = city;
			this.country = country;
		}
		public String getCountry() {
			return country;
		}
		@Override
		public String toString() {
			return "City [city=" + city + ", country=" + country + "]";
		}
		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + getOuterType().hashCode();
			result = prime * result + ((city == null) ? 0 : city.hashCode());
			result = prime * result
					+ ((country == null) ? 0 : country.hashCode());
			return result;
		}
		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			City other = (City) obj;
			if (!getOuterType().equals(other.getOuterType()))
				return false;
			if (city == null) {
				if (other.city != null)
					return false;
			} else if (!city.equals(other.city))
				return false;
			if (country == null) {
				if (other.country != null)
					return false;
			} else if (!country.equals(other.country))
				return false;
			return true;
		}
		private ResultSetStreamTest getOuterType() {
			return ResultSetStreamTest.this;
		}
	}

	private String[][] data = new String[][]{
			{"Karachi", "Pakistan"},
			{"Istanbul", "Turkey"},
			{"Hong Kong", "China"},
			{"Saint Petersburg", "Russia"},
			{"Sydney", "Australia"},
			{"Berlin", "Germany"},
			{"Madrid", "Spain"}
		};

	private int timesCalled;
	private PreparedStatement mockPST;
	private ResultSet mockRS;

	@Before
	public void setup() throws SQLException{
		timesCalled = -1;
		mockRS = mock(ResultSet.class);
		mockPST = mock(PreparedStatement.class);

		when(mockRS.next()).thenAnswer(new Answer<Boolean>() {

			@Override
			public Boolean answer(InvocationOnMock invocation) throws Throwable {
				if (timesCalled++ &gt;= data.length)
					return false;
				return true;
			}
		});

		when(mockRS.getString(eq("city"))).thenAnswer(new Answer<String>() {

			@Override
			public String answer(InvocationOnMock invocation) throws Throwable {
				return data[timesCalled][0];
			}
		});
		when(mockRS.getString(eq("country"))).thenAnswer(new Answer<String>() {

			@Override
			public String answer(InvocationOnMock invocation) throws Throwable {
				return data[timesCalled][1];
			}
		});

		when(mockPST.executeQuery()).thenReturn(mockRS);
	}

	@Test
	public void simpleTest() throws SQLException{

		try (Stream<City> testStream = new ResultSetStream<City>().getStream(mockPST,
				(ResultSet rs) -> {try {
					return new City(rs.getString("city"), rs.getString("country"));
				} catch (Exception e) {
					return null;
				}})){

			Iterator<City> cities = testStream.filter(
					city -> !city.getCountry().equalsIgnoreCase("China"))
					.limit(3).iterator();

			assertTrue(cities.hasNext());
			assertEquals(new City("Karachi", "Pakistan"), cities.next());

			assertTrue(cities.hasNext());
			assertEquals(new City("Istanbul", "Turkey"), cities.next());

			assertTrue(cities.hasNext());
			assertEquals(new City("Saint Petersburg", "Russia"), cities.next());

			assertFalse(cities.hasNext());
		}

	}

}

Download full source code on Github.

Java yield-like using Stream API

08/11/2014 1 comment

Several programming languages, such as Ruby or Python to name a few, provides the yield command. Yield provides an effective way, in terms of memory consumption, to create series of values, by generating such values on demand. More information on Python Yield.

Let’s consider a class or method requiring a huge amount of secure random integers. The classical approach would be to create an array or collection of such integers. Yield provides two major advantages over such approach:

  • yield does not require to know the length of the series in advance.
  • yield does not require to store all values in memory.

Fortunately, yield features can be used in Java 8 thanks to Stream API:

 

 

import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Date;
import java.util.function.Supplier;
import java.util.stream.Stream;

public class Yield {

	private static final Integer RANDOM_INTS = 10;

	public static void main(String[] args) {

		try (Stream randomInt = generateRandomIntStream()){
			Object[] randomInts = randomInt.limit(RANDOM_INTS)
                                .sorted().toArray();
			for (int i = 0; i < randomInts.length;i++)
				System.out.println(randomInts[i]);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
	}

	private static Stream generateRandomIntStream()
           throws NoSuchAlgorithmException{
		return Stream.generate(new Supplier() {

			final SecureRandom random = SecureRandom
                                .getInstance("SHA1PRNG");
			boolean init = false;
			int numGenerated = 0;

			@Override
			public Integer get() {
				if (!init){
					random.setSeed(new Date().getTime());
					init = true;
					System.out.println("Seeding");
				}
				final int nextInt = random.nextInt();
				System.out.println("Generated random "
                                         + numGenerated++
                                         + ": " + nextInt);
				return nextInt;
			}

		});
	}

}

Following is the output after provided code snippet is executed:

Seeding
Generated random 0: -896358073
Generated random 1: -1268521873
Generated random 2: 9627917
Generated random 3: -2106415441
Generated random 4: 935583477
Generated random 5: -1132421439
Generated random 6: -1324474601
Generated random 7: -1768257192
Generated random 8: -566921081
Generated random 9: 425501046
-2106415441
-1768257192
-1324474601
-1268521873
-1132421439
-896358073
-566921081
9627917
425501046
935583477

It is easy to see that Supplier is only instantiated one. Of course, we can take advantage of all Stream API features such as limit() and sorted().

The line randomInt.limit(RANDOM_INTS).sorted().toArray() triggers the generation of RANDOM_INTS values which are then sorted and stored as an array.

Compile-time checking JPA queries

JPA provides several alternatives for querying data. Such alternatives may be classified attending to a variety of criteria, eg, language used (SQL vs JPQL) or whether queries are static (compilation time) or dynamic (execution time).

Static queries are defined using annotations @NamedQuery (javax.persistence.NamedQuery) and @NamedQueries (javax.persistence.NamedQueries) in the @Entity class definition itself:

 @NamedQuery(
            name="findAllCustomersWithName",
            query="SELECT c FROM Customer c WHERE c.name LIKE :custName"
    )

On the other hand, EntityManager provides methods createQuery(…) y createNativeQuery(…) which take either a JPQL or a SQL query, respectively.

Thus, queries can be defined both in compilation or execution time.

(Note: It is advisable to always use parametrized queries using methods setParameter(…) from Query to avoid SQL Injection vulnerabilities.

Criteria API

However, JPA provides an alternative approach to query objects: Criteria API. Indeed, one of the motivations to switch to JPA is to deal with objects rather than SQL dialects, isn’t it ?

Let’s look a sample code.

Entity definition:

@Entity
public class User {

 @Id
 private Integer userId;

 @Basic
 @Column(length=15, nullable=false)
 private String name;

 @Basic
 @Column(length=64, nullable=false)
 private String userDigestedPasswd;

 @Basic
 @Column(length=50, nullable=true)
 private String email;

 @Basic
 @Column(nullable=false)
 public Integer privilegeLevel;

 @Basic
 @Column(nullable=false)
 private Boolean active;
}

Let’s query db and check results (using JUnit):

public class UserTest {
 @Test
 public void testUserCriteria(){
EntityManagerFactory emf = null;
EntityManager em = null;
try {
  emf = Persistence.createEntityManagerFactory("criteria");
  em = emf.createEntityManager();
  final CriteriaBuilder cb = em.getCriteriaBuilder();
  final CriteriaQuery<User> q = cb.createQuery(User.class);
  final Root<User> users = q.from(User.class);
  final Predicate condition = cb.equal(users.get("privilegeLevel"), 5);
  q.select(users).where(condition).orderBy(cb.asc(users.get("userId")));
  em.getTransaction().begin();
  List<User> result = em.createQuery(q).getResultList();
  em.getTransaction().commit();

  assertNotNull(result);
  assertEquals(2, result.size());

  assertEquals(1, (int)result.get(0).getUserId());
  assertEquals("Pepe", result.get(0).getName());

  assertEquals(3, (int)result.get(1).getUserId());
  assertEquals("Dolores", result.get(1).getName());} catch (Exception e) {
  fail("Unexpected Exception " + e.getMessage());
} finally {
  if (em != null)
    em.close();
  if (emf != null)
    emf.close();
}
}
}

Following lines show query creation:

final CriteriaBuilder cb = em.getCriteriaBuilder();
final CriteriaQuery<User> q = cb.createQuery(User.class);
final Root<User> users = q.from(User.class);
final Predicate condition = cb.equal(users.get("privilegeLevel"), 5);
q.select(users).where(condition).orderBy(cb.asc(users.get("userId")));

First of all, get a CriteriaBuilder from an EntityManager. Then, get a CriteriaQuery instance, setting the class to hold results. In our case, User.class:

final CriteriaBuilder cb = em.getCriteriaBuilder();
final CriteriaQuery<User> q = cb.createQuery(User.class);

Following, the Entity to run the query against must be set:

final Root<User> users = q.from(User.class);

Now it’s time to set query matching conditions. In the sample code, the condition is just attribute privilegeLevel to be equals to 5:

final Predicate condition = cb.equal(users.get("privilegeLevel"), 5);

Finally, query is built adding conditions on Root. Grouping and sorting options may be set too (ie, ascending sorting is set on userId):

q.select(users).where(condition).orderBy(cb.asc(users.get("userId")));

Please have a look at CriteriaBuilder for different options. Grouping and sorting options may be found at CriteriaQuery.

Using metamodel for compile-time checking

Note the query we have just build requires to keep track of object attributes names. Eg, to build the query, the name of the attribute privilegeLevel is used. However, if attribute name were changed later, the code would compile and only fail at runtime:

final CriteriaQuery<User> q = cb.createQuery(User.class);
final Root<User> users = q.from(User.class);
final Predicate condition = cb.equal(users.get("privilegeLevel"), 5);
q.select(users).where(condition).orderBy(cb.asc(users.get("userId")));

That is no good.

Fortunately, using metamodel, we will be able to build compile-time checked queries. A brief introduction can be found at The Java EE6 Tutorial.

Using metamodel, the code will reference an SingularAttribute of the object rather than using a String holding the object attribute name. So, if object attribute were changed later, the compiler would flag it for us.

First of all, the correspondent metamodel class (EntityType) must be created. Although it can achieved by several ways, probably the easiest one, for openJPA implementation, is to add a openJPA build flag:  -Aopenjpa.metamodel=true.

So we have the class User_ created, which is the correspondent metamodel class for User:

* Generated by OpenJPA MetaModel Generator Tool. **/
package com.wordpress.tododev.criteria.entities;
import javax.persistence.metamodel.SingularAttribute;
@javax.persistence.metamodel.StaticMetamodel
(value=com.wordpress.tododev.criteria.entities.User.class)
@javax.annotation.Generated
(value="org.apache.openjpa.persistence.meta.AnnotationProcessor6",date="Mon Mar 04 16:47:46 CET 2013")
public class User_ {
 public static volatile SingularAttribute<User,Boolean> active;
 public static volatile SingularAttribute<User,String> email;
 public static volatile SingularAttribute<User,String> name;
 public static volatile SingularAttribute<User,Integer> privilegeLevel;
 public static volatile SingularAttribute<User,String> userDigestedPasswd;
 public static volatile SingularAttribute<User,Integer> userId;
}

If such class were added to code repo, any later change to class User would remain unnoticeable. Moreover, it is not a good idea to add auto-generated items to code versioning systems.

Using ant, maven or similar tools, a target could be added to create metamodel classes. Such target should be executed after any change to JPA Entities.

Also possible to use IDE for that. Eg, for those using Eclipse, just need to add the already mentioned compilation flag to Properties->Java Compiler->Annotation Processor and the lib (jar) containing the Annotation Processor for the chosen JPA implementation to section Factory Path within Annotations Processor (could lead to compilation issues in auto mode, provided that metamodel class must be compiled before the code using it).

Let us add another test to the suite. This one will not provide a String containing the attribute name, but use the metamodel class instead:

@Test
 public void testUserCriteriaMetaModel(){
 EntityManagerFactory emf = null;
 EntityManager em = null;
 try {
 emf = Persistence.createEntityManagerFactory("criteria");
 em = emf.createEntityManager();
 final CriteriaBuilder cb = em.getCriteriaBuilder();
 final CriteriaQuery<User> q = cb.createQuery(User.class);
 final Metamodel m = em.getMetamodel();
 final Root<User> user = q.from(m.entity(User.class));
 final Predicate condition = cb.equal(user.get(User_.privilegeLevel), 5);
 q.select(user).where(condition).orderBy(cb.asc(user.get(User_.userId)));

 em.getTransaction().begin();
 List<User> result = em.createQuery(q).getResultList();
 em.getTransaction().commit();

 assertNotNull(result);
 assertEquals(2, result.size());

 assertEquals(1, (int)result.get(0).getUserId());
 assertEquals("Pepe", result.get(0).getName());

 assertEquals(3, (int)result.get(1).getUserId());
 assertEquals("Dolores", result.get(1).getName());
} catch (Exception e) {
 fail("Unexpected Exception " + e.getMessage());
 } finally {
 if (em != null)
 em.close();
 if (emf != null)
 emf.close();
 }
 }

More relevant changes are user.get(User_.privilegeLevel) instead of users.get(“privilegeLevel”) and  user.get(User_.userId) instead of  users.get(“userId”).

Download source code from GitHub

Creación de consultas dinámicas en JPA sin SQL (ni JPQL): Usando el metamodelo

En la entrada anterior vimos cómo realizar consultas JPA sin escribir código SQL. Sin embargo,  echemos un vistazo a una porción concreta del código que usamos en aquel momento:

  final CriteriaQuery<User> q = cb.createQuery(User.class);
  final Root<User> users = q.from(User.class);
  final Predicate condition = cb.equal(users.get("privilegeLevel"), 5);
  q.select(users).where(condition).orderBy(cb.asc(users.get("userId")));

Puede observarse como, en ciertos lugares, se obtienen valores de atributos del objeto User, en concreto, privilegeLevel y userId, haciendo referencia al nombre del dicho atributo. Este enfoque tiene el problema de que no se realizan comprobaciones en tiempo de ejecución. Dicho de otro modo, si, por ejemplo,  se cambiase el nombre del atributo userId a user_id, el código seguiría siendo correcto desde el punto de vista del compilador. Sin embargo, al ejecutarlo, se producirían errores al no existir tal atributo.
Una posible solución consiste en usar el metamodelo de Java. Una introducción, con ejemplos no muy afortunados, desde mi punto de vista, puede encontrarse en The Java EE6 Tutorial.

El truco consiste en acceder a los atributos del objeto usando el metamodelo, de manera que un cambio en cualquiera de los atributos del objeto sería detectado mediante un fallo de compilación. Lo primero que hay que hacer es generar la clase del metamodelo correspondiente, la EntityType. Hay varias formas de hacerlo, aunque quizás la mas sencilla sea indicarlo con el flag de compilación correspondiente. Por ejemplo, para openJPA, el flag es  -Aopenjpa.metamodel=true. 

Se genera la clase User_, que no es mas que la clase de  metamodelo de User, siguiendo el estándar de nomenclatura .

* Generated by OpenJPA MetaModel Generator Tool. **/
package com.wordpress.tododev.criteria.entities;
import javax.persistence.metamodel.SingularAttribute;
@javax.persistence.metamodel.StaticMetamodel
(value=com.wordpress.tododev.criteria.entities.User.class)
@javax.annotation.Generated
(value="org.apache.openjpa.persistence.meta.AnnotationProcessor6",date="Mon Mar 04 16:47:46 CET 2013")
public class User_ {
 public static volatile SingularAttribute<User,Boolean> active;
 public static volatile SingularAttribute<User,String> email;
 public static volatile SingularAttribute<User,String> name;
 public static volatile SingularAttribute<User,Integer> privilegeLevel;
 public static volatile SingularAttribute<User,String> userDigestedPasswd;
 public static volatile SingularAttribute<User,Integer> userId;
}

Quizás la primera opción que se viene a la cabeza sea añadir este código autogenerado al sistema de control de versiones. Pero no suele ser buena idea añadir código autogenerado y, sobre todo, una modificación posterior en los atributos de User pasaría desapercibida por el compilador a menos que se generase de nuevo la clase User_.  En el caso de usar ant, podría solucionarse añadiendo un target específico que genere las clase del metamodelo. Dicho target debería ejecutarse cada vez que se realizara alguna modificación en cualquiera de las Entities JPA de la aplicación.

Otra opción consiste en instruir al IDE para generar código de acuerdo con las anotaciones. En Eclipse, hay que añadir el flag de compilación ya mencionado en  Properties->Java Compiler->Annotation Processor y, a continuación, añadir el jar que contiene el Annotation Processor de la implementación JPA elegida en la sección Factory Path (dentro de Annotations Processor). El problema es que, en este caso, la clase de metamodelo User_ se genera al compilar, pero para compilar se necesita la clase del metamodelo, y llegamos al dilema del huevo o la gallina.

En cualquier caso, una vez se disponga de la clase de metamodelo, se puede añadir otro test a la suite anterior que proporciona el mismo resultado sin necesidad de pasar una cadena con el nombre del atributo:

@Test
 public void testUserCriteriaMetaModel(){
 EntityManagerFactory emf = null;
 EntityManager em = null;
 try {
 emf = Persistence.createEntityManagerFactory("criteria");
 em = emf.createEntityManager();
 final CriteriaBuilder cb = em.getCriteriaBuilder();
 final CriteriaQuery<User> q = cb.createQuery(User.class);
 final Metamodel m = em.getMetamodel();
 final Root<User> user = q.from(m.entity(User.class));
 final Predicate condition = cb.equal(user.get(User_.privilegeLevel), 5);
 q.select(user).where(condition).orderBy(cb.asc(user.get(User_.userId)));

 em.getTransaction().begin();
 List<User> result = em.createQuery(q).getResultList();
 em.getTransaction().commit();

 assertNotNull(result);
 assertEquals(2, result.size());

 assertEquals(1, (int)result.get(0).getUserId());
 assertEquals("Pepe", result.get(0).getName());

 assertEquals(3, (int)result.get(1).getUserId());
 assertEquals("Dolores", result.get(1).getName());
} catch (Exception e) {
 fail("Unexpected Exception " + e.getMessage());
 } finally {
 if (em != null)
 em.close();
 if (emf != null)
 emf.close();
 }
 }

Los cambios importantes están en las líneas en negrita. Sobre todo,  user.get(User_.privilegeLevel), en lugar de users.get(“privilegeLevel”) y user.get(User_.userId) en lugar de users.get(“userId”).

Podéis encontrar el código fuente actualizado en GitHub.

Actualizar a JDK7 en Linux sin romper /etc/alternatives

Como seguramente ya sabéis, debido a temas relacionados con licencias, el JDK7 de Sun (digo, Oracle) no estará incluido en los repositorios de Debian o Ubuntu. Esto no quiere decir que no se pueda instalar JDK7 en Linux, ya que puede descargarse de Sun en forma de .tgz e instalarlo.

Normalmente la instalación de los JDK se realizaba mediante el correspondiente paquete .deb. Dichos paquetes, además de instalar el JDK en sí, realizaban otra serie de operaciones, entre las que se encuentran actualizar ciertos componentes del sistema. Entre dichos componentes se encuentra /etc/alternatives, que consiste en el mantenimiento de una serie de enlaces simbólicos que permiten, en este caso, usar las herramientas del nuevo JDK sin tener que modificar los ejecutables o paths ya configurados en otras aplicaciones.

Sin embargo, al no instalarse el nuevo JDK como un paquete .deb, tendremos que actualizar el sistema  /etc/alternatives a mano.

En primer lugar, veamos el estado actual del sistema:

yo@localhost:~$ update-alternatives --list java
/usr/lib/jvm/java-6-openjdk/jre/bin/java
/usr/lib/jvm/java-6-sun/jre/bin/java

En este caso vemos las alternativas para el comando java, que consisten en la proporcionada por OpenJDK y la máquina de Sun en su versión 6. Sin embargo, el JDK no es sólo java, contiene una completa serie de utilidades. Sin  ir mas lejos, para compilar, necesitaremos javac. Veamos:

yo@localhost:~$ update-alternatives --list javac
/usr/lib/jvm/java-6-openjdk/bin/javac
/usr/lib/jvm/java-6-sun/bin/javac

Además podemos ver cuál es la versión que se usará por defecto. Por ejemplo, para javac obtenemos:

yo@localhost:~$ update-alternatives --display javac
javac - modo manual
el enlace apunta actualmente a /usr/lib/jvm/java-6-sun/bin/javac
/usr/lib/jvm/java-6-openjdk/bin/javac - prioridad 1061
esclavo javac.1.gz: /usr/lib/jvm/java-6-openjdk/man/man1/javac.1.gz
/usr/lib/jvm/java-6-sun/bin/javac - prioridad 1062
esclavo javac.1.gz: /usr/lib/jvm/java-6-sun/man/man1/javac.1.gz
Actualmente la «mejor» versión es /usr/lib/jvm/java-6-sun/bin/java.

La salida indica que el javac por defecto es el que nos proporciona el JDK6.

Como es de esperar, el sistema /etc/alternatives proporciona un interfaz para añadir nuevas alternativas. Sin embargo, un paquete como los JDK requiere actualizar muchas “alternativas” y sus “esclavas” de páginas de documentación.

Para actualizar varias máquinas, o si no quieres complicarte la vida usando /etc/alternatives directamente, puedes usar el script que proporcionamos a continuación. Se le pasa como parámetro el directorio donde has instalado el JDK7 (sin la / del final, es un poco tosco, la verdad) y genera un archivo update-alternatives, para añadir las nuevas opciones, y otro set-alternative, que las pone como valor por defecto. Echando un vistazo a estos archivos puedes hacerte una idea de la cantidad de “alternativas” que se actualizarán.

Después de ejecutarlo tu sistema debería haberse actualizado de la siguiente manera:

yo@localhost:~$ update-alternatives --list javac
/usr/lib/jvm/java-6-openjdk/bin/javac
/usr/lib/jvm/java-6-sun/bin/javac
/usr/lib/jvm/jdk1.7.0_03/bin/javac

yo@localhost:~$ update-alternatives --display javac
javac - modo manual
el enlace apunta actualmente a /usr/lib/jvm/jdk1.7.0_03/bin/javac
/usr/lib/jvm/java-6-openjdk/bin/javac - prioridad 1061
esclavo javac.1.gz: /usr/lib/jvm/java-6-openjdk/man/man1/javac.1.gz
/usr/lib/jvm/java-6-sun/bin/javac - prioridad 1062
esclavo javac.1.gz: /usr/lib/jvm/java-6-sun/man/man1/javac.1.gz
/usr/lib/jvm/jdk1.7.0_03/bin/javac - prioridad 1063
esclavo javac.1: /usr/lib/jvm/jdk1.7.0_03/man/man1/javac.1
Actualmente la «mejor» versión es /usr/lib/jvm/jdk1.7.0_03/bin/javac.

Sin mas dilación, el script. Ni que decir tiene que, como es habitual, si lo usas es por tu cuenta y riesgo, etc… En definitiva, que no nos culpes si algo sale mal 😉

#!/bin/bash

NEWDIR=$1; # without final slash please !!
LATEST=$((`update-alternatives --query java|grep Priority:|awk '{print $2}'|sort -n|tail -1`+1));

echo "Adding JDK from $1 with priority $LATEST";

BASH_FILE="update-alternatives";
UPDATE_FILE="set-alternative";

echo "#!/bin/bash" > $BASH_FILE;
echo "####" >> $BASH_FILE;
echo "####" >> $BASH_FILE;

echo "#!/bin/bash" > $UPDATE_FILE;
echo "####" >> $UPDATE_FILE;
echo "####" >> $UPDATE_FILE;
# man update-alternatives
# update-alternatives --install link name path priority [--slave link name path]...

for f in /etc/alternatives/*
do
fname=`echo $f | awk -F'/' '{print $4}' `;

CMD="update-alternatives --install /usr/bin/";
BIN="bin/$fname";
MAN="man/man1/${fname}.1";
MANGZ="man/man1/${fname}.1.gz";

if [ -f $NEWDIR/$BIN ] ; then
echo "# Adding $fname" >> $BASH_FILE;
CMD="${CMD}${fname} ${fname} $NEWDIR/$BIN $LATEST ";

echo "update-alternatives --set ${fname} $NEWDIR/$BIN">> $UPDATE_FILE;

if [ -f $NEWDIR/$MAN ] ; then
echo "# Adding slave ${fname}.1" >> $BASH_FILE;
CMD="${CMD} --slave /usr/share/$MAN ${fname}.1 $NEWDIR/$MAN";
fi

if [ -f $NEWDIR/$MANGZ ] ; then
echo "# Adding slave ${fname}.1.gz" >> $BASH_FILE;
CMD="${CMD} --slave /usr/share/$MANGZ ${fname}.1.gz $NEWDIR/$MANGZ";
fi
echo "$CMD" >> $BASH_FILE;
fi
done

exit;

Conexiones seguras SSL y certificado cliente

04/25/2012 Leave a comment

Conexiones seguras SSL con certificado cliente

Primero vamos a ver los pasos necesarios para crear, firmar y configurar un certificado de servidor que se utilizará para cifrar la conexión. Y luego vamos a crear y configurar otro certificado que se utilizará en la parte cliente como certificado cliente para identificar el cliente que hace la petición.

En esta guía vamos a utilizar un Tomcat 7.0.23, java 7u3 y Apache Httpclient 4.1.1.

Antes de empezar vamos a matizar algunos conceptos que vamos a utilizar. Para realizar las conexiones SSL y autenticarnos con los certificados de cliente utilizaremos diferentes entradas del keystore. Cada una de estas entradas es un par clave privada clave pública, donde la clave pública se encuentra envuelta en un certificado X.509 v3 que por defecto está autofirmado (esto luego lo cambiaremos), esta cadena de certificados es guardada como un único elemento. El exportar una entrada lo que estamos exportando es el certificado que envuelve la clave pública. En la importación de certificados hay dos casos que se explican más abajo.

Nota: En algunos códigos de ejemplo se han tenido que meter saltos de línea para que el texto entrase. Es posible que estos saltos de línea tengan que ser eliminados para el correcto funcionamiento de los comandos.

Conexión SSL

Generar las claves, certificado SSL

Primero tenemos que crearnos un par de claves en nuestro keystore que se utilizarán como certificado SSL en el servidor

keytool -genkeypair -keystore server.keystore -alias certSSL -dname CN=localhost
  • -keystore: Es la ruta al archivo keystore que contiene la nueva entrada que se va a generar. Este será el archivo que leerá nuestro servidor para cifrar la conexión.
  • -alias: Es el alias con el que vamos a identificar a está entrada dentro del keystore.
  • -dname: Es el nombre del host del servidor que va a cifrar la conexión en formato CN=host_name. Cuando el cliente haga una petición a nuestro servidor resolverá en su /etc/hosts el host o ip que pongamos en la URL y utilizará ese nombre para validar el certificado del servidor. Si no coincide, no aceptará la petición.

Primero nos pedirá una contraseña para el keystore si el keystore no existe y luego nos pedirá confirmarla. Luego nos pedirá una contraseña para la clave que va a generar y que la volvamos a escribir, si no ponemos ninguna utilizará la del keystore.

El certificado que hemos generado arriba está autofirmado. Eso quiere decir que no ha sido firmada por otra clave (privada). Es muy útil que tengamos nuestro certificado firmado por otro que funcione como autoridad certificadora (CA), de esta forma si el cliente tiene esa CA en su baúl (truststore), todo certificado firmado por esa CA será de confianza y no tendremos que ir añadiendolos independientemente. Luego hablaremos de cómo añadir CA al baúl cliente.

Firmar certificado

Para firmar un certificado primero tenemos que hacer una petición de firmado de certificado (CSR) del certificado que queremos firmar.

keytool -certreq -keystore server.keystore -alias certSSL -file certSSL.csr
  • -keystore: Es la ruta al archivo keystore que contiene el certificado que queremos firmar.
  • -alias: Alias que identifica la entrada que contiene el certificado que vamos a firmar.
  • -file: Ruta al archivo que va a guardar la petición de firmado.

En este proceso te pedirá la contraseña del keystore y si la contraseña de la clave es distinta también te la pedirá. Ahora tenemos dos opciones le pedimos a una autoridad certificadora externa que nos firme nuestro CSR (VeriSign, Thawte,…) o lo firmamos nosotros con una clave privada nuestra.

Firma CA externa

Si elegimos a la autoridad externa, tendremos que enviarle el CSR a parte de otros datos que nos pida. La CA nos devolverá un nuevo certificado, que es el nuestro firmado por ella.

Firma con nuestro CA

Si no tenemos una clave privada para firmar, tendremos que generarla. Se hace igual que la que hemos generado antes

keytool -genkeypair -keystore ca.keystore -alias myca -dname CN=CA
  • -keystore: Es la ruta al archivo keystore que contiene la clave que se va a generar. Es recomendable que sea distinto al que hemos usado para SSL. Luego exportaremos el este certificado y se lo añadiremos al keystore de SSL con un alias nuevo (por la forma de añadirlo se guardará como una entrada de certificado de confianza).
  • -alias: Es el alias con el que vamos a identificar a está entrada dentro del keystore.
  • -dname: Puede ser lo que quieras.

Este comando te pedirá la contraseña del keystore y luego la contraseña de la clave que acaba de generar. Ahora firmamos el CSR con nuestra clave privada bajo el alias myca.

keytool -gencert -keystore ca.keystore -alias myca -ext san=dns:ca1
 -infile certSSL.csr -outfile signedCert.cert
  • -keystore: Es la ruta al archivo keystore que contiene la clave que antes hemos generado para firmar la CSR.
  • -alias: Alias de la clave que vamos a usar para firmar la CSR.
  • -ext: Extensiones X.509 que será embebidas en el certificado que vamos a firmar (fuera del ámbito del documento).
  • -infile: Ruta al archivo que tiene la solicitud de firma CSR.
  • -outfile: Ruta al archivo en el que se guardará el certificado (certSSL) firmado por nuestro CA.

En el proceso te pedirá la contraseña del keystore y si es distinta la contraseña de la clave myca.

Añadir certificado firmado

Da lo mismo el método de firmado elegido, al final tenemos un nuevo archivo (el que nos devuelva la CA externa o el que hemos generado nosotros signedCert.cert) que contiene la cadena de cerificados. Ahora hay que añadir ese certificado a nuestro keystore.

keytool -importcert -keystore server.keystore -file signedCert.cert -alias certSSL
  • -keystore: Es la ruta al archivo keystore donde queremos guardar la nueva clave firmada.
  • -file: Ruta al archivo que tiene la clave firmada.
  • -alias: Alias de la clave sin firmar que va a ser sobrescrito con la nueva clave firmada.

En el proceso te pedirá la contraseña del keystore y, si es distinta, la contraseña de la entrada con alias certSSL.

Si faltase algún certificado de los que componen la cadena de certificados que estamos añadiendo daría un error y no lo añadiría. Habría que añadir los certificados que faltasen (ver Añadir certificado CA).

Configurar servidor

Ya tenemos nuestro keystore con la cadena de certificados y clave privada que vamos a utilizar para la conexión SSL. Ahora hay que configurar el servidor para que utilice ese certificado y clave privada. En el server.xml definimos un nuevo conector de la siguiente manera

<Connector protocol="org.apache.coyote.http11.Http11Protocol" port="18081" 
minSpareThreads="5" enableLookups="true" disableUploadTimeout="true" 
acceptCount="100" maxThreads="200" scheme="https" secure="true" 
SSLEnabled="true" keystoreFile="server.keystore" keystorePass="cambiala" 
keyAlias="certSSL" keyPass="cambialaTambien" sslProtocol="TLS" />
  • port: Puerto donde va a escuchar nuestras peticiones.
  • keystoreFile: Es la ruta al archivo keystore donde tenemos guardada la cadena de certificados y clave privada que vamos a usar para la conexión SSL.
  • keystorePass: Contraseña del keystore.
  • keyAlias: El alias de la entrada del keystore que vamos a utilizar para cifrar la conexión.
  • keyPass: Contraseña de la entrada identificada con el alias especificado en keyAlias.

Configurar cliente

Si hemos firmado el certificado que el servidor utiliza para la conexión SSL con una CA externa, entonces no tenemos que hacer nada especial ya que el certificado de esa CA externa seguramente ya esté en baúl de confianza. Pero si hemos utilizado nuestro propio certificado, tenemos que añadir ese certificado al baúl de confianza que va a utilizar nuestro cliente. Hay distintas formas de hacer esto, voy a explicar la más localizada, sólo afectará a nuestro cliente. Primero exportamos el nuestro certificado de CA como se ha hecho arriba, pero en vez de importarlo en el keystore del sevidor lo añadimos al truststore del cliente

keytool -importcert -keystore client.truststore -file ca.cer -alias certSSL
  • -keystore: Ruta al archivo keystore donde vamos a guardar certificado que firma la clave utilizada para la conexión SSL.
  • -file: Ruta del archivo donde se esta el certificado.
  • -alias: Alias con el que se va a guardar la entrada del certificado de CA.

Ahora tenemos que decir a nuestro código que utilice este keystore como truststore. Primero obtenemos el truststore

FileInputStream instream = new FileInputStream(new File(TRUSTSTORE_PATH)
KeyStore truststore  = KeyStore.getInstance(KeyStore.getDefaultType());
truststore.load(instream, TRUST_STORE_PASS.toCharArray());

Luego creamos una factoría de sockets que utilice nuestro truststore y un esquema (scheme) para https que utilice esta factoría de sockets. Y registramos este esquema en el gestor de conexiones (connectionManager) de nuestro cliente.

SSLSocketFactory socketFactory = new SSLSocketFactory(truststore);
Scheme sch = new Scheme("https", 18081, socketFactory);
client.getConnectionManager().getSchemeRegistry().register(sch);

El código resultante sería algo así:

public class Client {

	private final static String URL = "https://localhost:18081/appSSL";
	private final static String TRUESTORE_PATH = "client.truststore";
	private static final String KEY_STORE_PASS = "cambialaTrust";

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		DefaultHttpClient client = new DefaultHttpClient();

		try (FileInputStream instream = new FileInputStream(new File(
                            TRUESTORE_PATH));){
			KeyStore truststore  = KeyStore.getInstance(
                            KeyStore.getDefaultType());

		        truststore.load(instream, KEY_STORE_PASS.toCharArray());

	        	SSLSocketFactory socketFactory = 
                            new SSLSocketFactory(truststore);
	        	Scheme sch = new Scheme("https", 18081, socketFactory);
		        client.getConnectionManager().getSchemeRegistry()
                            .register(sch);

			HttpGet httpget = new HttpGet(URL);
			HttpResponse response;

			response = client.execute(httpget);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
			    BufferedReader reader = new BufferedReader(
                                new InputStreamReader(entity.getContent()));

			    String text;
			    while ((text = reader.readLine()) != null)
			    	System.out.println(text);
			}
		} catch (IOException | CertificateException | KeyStoreException 
                             | NoSuchAlgorithmException | KeyManagementException 
                             | UnrecoverableKeyException e) {
			e.printStackTrace();
		}

	}

}

Certificado cliente

Una de las formas que tenemos de identificar al cliente que está haciendo la petición es mediante un certificado de cliente. El cliente utiliza el par certificado-clave privada para identificarse contra el servidor.

Generar par certificado-clave privada

La entrada se genera igual que para el caso de la conexión SSL, pero en este caso el valor que pongamos en el parámetro -dname va a ser lo que luego nos identificará en el servidor.

keytool -genkeypair -keystore client.keystore -alias clientCert -dname CN=Nikola
  • -keystore: Es la ruta al archivo keystore que va contener el par certificado-clave que se va a generar.
  • -alias: Es el alias con el que vamos a identificar a está entrada dentro del keystore.
  • -dname: Es el nombre que luego nos identificará en el servidor.

Primero nos pedirá una contraseña para el keystore si el keystore no existe y luego nos pedirá confirmarla. Luego nos pedirá una contraseña para la entrada que va a generar y que la volvamos a escribir, si no ponemos ninguna utilizará la del keystore.

Configuración servidor

Esto se puede hacer de dos formas según quieras que sea el servidor o la aplicación quien autentique al cliente.

Autenticación por aplicación

En el server.xml tenemos que modificar nuestro conector SSL añadiéndole los siguientes atributos:

  • truststoreFile=“client.keystore”
  • truststorePass=“cambiala”
  • clientAuth=“false”

quedaría así:

<Connector protocol="org.apache.coyote.http11.Http11Protocol" port="18081" 
minSpareThreads="5" enableLookups="true" disableUploadTimeout="true" 
acceptCount="100" maxThreads="200" scheme="https" secure="true" 
SSLEnabled="true" keystoreFile="/var/lib/tomcat7/conf/pruebando" 
keystorePass="asdasd" keyAlias="ssl" keyPass="asdasd" 
truststoreFile="client.keystore" truststorePass="cambiala" clientAuth="false" 
sslProtocol="TLS" />
  • truststoreFile: Ruta al archivo keystore con los certificados de los clientes que vamos a autenticar.
  • truststorePass: Contraseña del keystore.

En el web.xml de la aplicación tendríamos que añadir las restricciones de seguridad a los recursos de la aplicación e indicar el tipo de autenticación que queremos realizar. Podría ser algo así:

<login-config>
    <auth-method>CLIENT-CERT</auth-method>
    <realm-name>Mi realm</realm-name>
</login-config>

<security-role>
    <description>Cliente con certificado</description>
    <role-name>pruebaClientCert</role-name>
</security-role>

<security-constraint>
    <display-name>Toda la aplicacion</display-name>
    <web-resource-collection>
        <web-resource-name>Todo</web-resource-name>
        <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>pruebaClientCert</role-name>
    </auth-constraint>
</security-constraint>

Estás líneas en el web.xml indican que el método de autenticación va a ser por certificado de cliente (<auth-method>CLIENT-CERT</auth-method>) que el rol necesario para poder acceder a cualquier recurso de la aplicación es “pruebaClientCert”.

Y luego en donde estén definidos los usuarios las contraseñas y los roles tenemos que meter la siguiente entrada:

  • Nombre de usuario: Es el nombre que definimos el crear la clave del cliente en el parámetro -dname. (En nuestro ejemplo “CN=Nikola”).
  • Contraseña: null
  • Roles: Los roles a los que van a pertenecer a este cliente. (En nuestro caso, como mínimo, pruebaClientCert).

Para el caso del realm UserDatabaseRealm habría que añadir algo así:

<role rolename="pruebaClientCert"/>
...
<user username="CN=Nikola" password="null" roles="pruebaClientCert" />

Autenticación por servidor

Configuración cliente

Vamos a utilizar la entrada que hemos generado antes para identificar al cliente que hace la petición, para esto vamos a tener que decir a nuestro código que utilice este keystore. Primero obtenemos el keystore

FileInputStream instreamKey = new FileInputStream(new File(KEYSTORE_PATH)
KeyStore keystore  = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(instreamKey, KEYSTORE_PASS.toCharArray());

Luego modificamos la factoría de sockets que hemos creado antes para que utilice nuestro keystore.

SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore, KEYSTORE_PASS, 
trustStore);

El código resultante sería algo así:

public class Atacando {

	private final static String URL = "https://localhost:18081/appSSL";
	private final static String TRUSTSTORE_PATH = "client.truststore";
	private static final String TRUSTSTORE_PASS = "cambialaTrust";

	private final static String KEYSTORE_PATH = "client.keystore";
	private static String KEYSTORE_PASS = "cambiala";

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		DefaultHttpClient client = new DefaultHttpClient();

		try (FileInputStream instream = new FileInputStream(new File(
                              TRUSTSTORE_PATH));
			   FileInputStream instreamKey = 
                              new FileInputStream(new File(KEYSTORE_PATH));){
			KeyStore trustStore  = KeyStore.getInstance(
                              KeyStore.getDefaultType());
			KeyStore keyStore  = KeyStore.getInstance(
                              KeyStore.getDefaultType());

	                trustStore.load(instream, TRUSTSTORE_PASS.toCharArray());
	                keyStore.load(instreamKey, KEY_STORE_PASS.toCharArray());

	                SSLSocketFactory socketFactory = new SSLSocketFactory(
                               keyStore, KEYSTORE_PASS, trustStore);
         	        Scheme sch = new Scheme("https", 18081, socketFactory);
        	        client.getConnectionManager().getSchemeRegistry()
                               .register(sch);

			HttpGet httpget = new HttpGet(URL);
			HttpResponse response;

			response = client.execute(httpget);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
			    BufferedReader reader = new BufferedReader(
                                 new InputStreamReader(entity.getContent()));

			    String text;
			    while ((text = reader.readLine()) != null)
			    	System.out.println(text);
			}
		} catch (IOException | CertificateException | KeyStoreException 
                          | NoSuchAlgorithmException | KeyManagementException 
                          | UnrecoverableKeyException e) {
			e.printStackTrace();
		}
	}
}
%d bloggers like this: