Category: Uncategorized

HTTPS client with valid SSL certificate

Here is the code snippet for connecting to services with HTTPS & HTTP with valid keystore and trust store


Imports:

import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.core.io.ClassPathResource;

import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

// Method to build the http client with SSL & non SSL

public HttpClient buildHttpClient(ApplicationProperties properties) throws UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException {
CloseableHttpClient httpclient =
HttpClients.custom()
.setConnectionManager(poolingHttpClientConnectionManager(properties))
.setDefaultRequestConfig(getRequestConfig(properties.getSocketTimeOut(),properties.getConnectionTimeout(),properties.getReadTimeOut()))
.build();
return httpclient;
}

private RequestConfig getRequestConfig(int socketTimeOut, int connectTimeOut, int connectRequestTimeOut) {
return RequestConfig.custom().setSocketTimeout(socketTimeOut)
.setConnectTimeout(connectTimeOut)
.setConnectionRequestTimeout(connectRequestTimeOut).build();
}

private PoolingHttpClientConnectionManager poolingHttpClientConnectionManager(ApplicationProperties properties) throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException {
PoolingHttpClientConnectionManager httpClientConnectionManager = null;
if(properties.isSslEnabled()) {
/**
* Load the keystore
*/
final KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(loadCertificate(properties.getSslKeyStoreLocation()), properties.getSslKeyStorePassword().toCharArray());
/**
* Load the trust store
*/
final KeyStore myTrustStore = KeyStore.getInstance(properties.getSslTrustStoreType());
myTrustStore.load(loadCertificate(properties.getSslTrustStoreLocation()), properties.getSslTrustStorePassword().toCharArray());
SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
sslContextBuilder.loadTrustMaterial(myTrustStore, null);
sslContextBuilder.loadKeyMaterial(keyStore, properties.getSslKeyStorePassword().toCharArray());
SSLConnectionSocketFactory sslConnectionSocketFactory = null;
try {
/**
* Build SSL context
*/
sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContextBuilder.build());
} catch (NoSuchAlgorithmException | KeyManagementException e) {
}

Registry sslSocketFactoryRegistry = RegistryBuilder.create()
.register(HTTPS, sslConnectionSocketFactory)
.build();
httpClientConnectionManager = new PoolingHttpClientConnectionManager(
sslSocketFactoryRegistry);
} else {
/**
* default to non SSL context
*/
httpClientConnectionManager = new PoolingHttpClientConnectionManager();
}
httpClientConnectionManager.setMaxTotal(properties.getMaxTotal());
httpClientConnectionManager.setDefaultMaxPerRoute(properties.getMaxPerRoute());
return httpClientConnectionManager;
}

/**
* Method to load the certificates from the classpath location
* @param certificateLocation
* @return
* @throws IOException
*/
private InputStream loadCertificate(String certificateLocation) throws IOException {
ClassPathResource resource = new ClassPathResource(certificateLocation);
return resource.getInputStream();
}

Agile Scrum process improvements

Story Definition of Done  – Definition

Add a sub task as 6D’s (Not always all D’s applies to all stories then task owner can tell in scrum and move the story to closed)

    1. D  Design – Design the architecture/flow before start coding
    2. D  Develop – Do the actual coding for the given story
    3. D  Document – confluence/ Java doc wherever needed
    4. D’o Review – 2 Peer review
    5. D Deploy – In test server/ test space
    6. D Demo – To team/ larger audience if needed

4D’s – Individuals should follow for better task management 

  1. Do – Do the given task
  2. Delegate – If you are occupied delegate the task if someone can take
  3. Defer – If something cannot be done, Don’t accept it
  4. Delete – If it’s out of scope remove it

 

Points to consider before start of project:

  • Any Firewall port needs to be opened
  • Any SSL certificate needed
  • Any external team involved if so prepare Q & A / Schedule meeting and get clarified
  • Do we foresee any integration issues,
    • Are we the 1’st team to do this integration? Then be more proactive
    • Any system already integrated?
    • What are the challenges they faced?
    • Decide one way / two way SSL
    • If 2 ways SSL our certificate has to be shared with the other team and make sure they installed in their firewall/gateway/proxy server.
    • Use telnet/curl/other commands to ensure connectivity
  • Do integration testing of system with minimal feature like hello world/hard coded response
  • If you working on legacy application then be more careful with maven dependency version, don’t bring new dependency with latest version which may break existing code.

Dynamo DB Filtering

DynamoDb works on mainly HASH(partation) key and RANGE(Sort) key

Two types of index

LSI (Local Secondary Indexes)
– It is tightly attached to structure of the table.

– Should have the same hash key as the table, But will have different range key
GSI (Global Secondary Indexes)
– Is altogether different Hash and Range Key

We can have max 5 LSI and GSI per table.

Searching/ Filtering the records
We can apply the search based on range key
Code snippet to get the filtered record using QuerySpec

Here is the scenario,

We have a table EMPLOYEE and need to get the employee’s whose status is “ACTIVE” and joining date between “2017-01-01” and “2018-01-01”.
On top it filter based on name and no of days column with pagination support.
Dynamo DB has unique way of applying the filtering and it returns max 1MB of data at asuppor
This scenario covers most of the filtering concepts like,

  • With table name
  • With GSI index name
  • Key Conditional expression
  • Filter Expression
  • With name map
  • With value map
  • With reserved key word as column name.
  • Pagination (withExclusiveStartKey)

Code snippet to get the filtered record using QuerySpec, If you are looking for pagination support follow the next section.

String filter_Expression = "name = :v_name and noOfDay = :v_noOfDay";
Map value_Map = new LinkedHashMap();
Map name_Map = new LinkedHashMap();
//Status is a reserved keyword so so we need to create alias name and pass
name_Map.put("#v_status_name", "status");

value_Map.put(":v_startDate", "2017-01-01");
value_Map.put(":v_endDate", "2018-01-01" );
value_Map.put(":v_status", "ACTIVE");
value_Map.put(":v_name", "TEST");
value_Map.put(":v_noOfDay", "10");

QuerySpec spec = new QuerySpec();
spec.withKeyConditionExpression("#v_status_name = :v_status and createdDate between :v_startDate and :v_endDate ");
spec.withFilterExpression(filter_Expression)
.withNameMap(name_Map)
.withValueMap(value_Map);
spec.withNameMap(name_Map).withValueMap(value_Map);

Code snippet to get the filtered record using QueryRequest and QueryResult
It has the advantage of passing the LastEvaluatedKey(used for pagination)

AmazonDynamoDB amazonDynamoDB = AmazonDynamoDBClientBuilder.standard().build();
//One way
String filterExpression = "name = :v_name and noOfDay = :v_noOfDay";
Map<String, String> nameMap = new LinkedHashMap<>();
Map<String, AttributeValue> exclusiveStartKey = new HashMap<>();
Map<String,AttributeValue> expressionAttributeValues = new HashMap<>();
expressionAttributeValues.put(":v_startDate",new AttributeValue().withS("2017-01-01"));
expressionAttributeValues.put(":v_endDate",new AttributeValue().withS("2018-01-01"));
expressionAttributeValues.put(":v_status",new AttributeValue().withS("ACTIVE"));
QueryRequest queryRequest = new QueryRequest()
.withTableName("EMPLOYEE")
.withIndexName("empId")
.withKeyConditionExpression("#v_status_name = :v_status and createdDate between :v_startDate and :v_endDate ")
.withExpressionAttributeNames(nameMap)
.withExpressionAttributeValues(expressionAttributeValues);
queryRequest.withFilterExpression(filterExpression);
//Construct the exclusiveStartKey based on the input you received for pagination from UI
exclusiveStartKey.put("status", new AttributeValue().withS("COMPLETED"));
if (!exclusiveStartKey.isEmpty()) {
queryRequest.withExclusiveStartKey(exclusiveStartKey);
}
QueryResult query = amazonDynamoDB.query(queryRequest);
List<Map<String, AttributeValue>> valueItems = query.getItems();
List<Map<String,Object>> convertedMap = objectConversion(valueItems);
//fasterxml.jackson.databind.ObjectMapper
ObjectMapper objectMapper = new ObjectMapper();
//TODO:convert convertedMap value to custom object model using objectMapper here
// Getting the overall count used by UI for pagination
QueryRequest countQuery = queryRequest.clone();
countQuery.withSelect(Select.COUNT);
QueryResult countResults = amazonDynamoDB.query(countQuery);
int overAllCount = countResults.getCount();
System.out.println("count :" + overAllCount);

private static List<Map<String,Object>> objectConversion(List<Map<String, AttributeValue>> dbValues) {
List<Map<String,Object>> tranformedMap = new ArrayList<>();
dbValues.stream()
.forEach(item -> {
Map<String, Object> map = new HashMap<>();
item.entrySet()
.iterator()
.forEachRemaining(e -> {
AttributeValue value = e.getValue();
Object val = null;
if (value.getS() != null) {
val = value.getS();
} else if (value.getM() != null) {
val = value.getM();
}
map.put(e.getKey(), val);
});
tranformedMap.add(map);
});
return tranformedMap;
}

How to customize the message in RabbitMQ while dead-lettering

When you are using Spring AMQP api to publish and consume the messages it provides the option to  consumer to Reject the message when we get AmqpRejectAndDontRequeueException.

Spring AMQP takes are of pushing the message to corresponding dead-letter exchange when this exception is occurred with status as Rejected.

But we don’t have any idea about which exception caused this particular message to be dead-letterd as spring amqp doesn’t provide it and it don’t have option to customize the message also.

Along with Spring-retry and spring AMQP api we can customize the message before its is dead-lettered.

https://stackoverflow.com/questions/33810450/how-to-specify-additional-info-on-a-rabbit-message-when-its-dead-lettered

https://docs.spring.io/spring-amqp/docs/latest_ga/reference/htmlsingle/#async-listeners

https://www.infobip.com/en/engineering/rabbitmq-message-processing-and-retry-logic

Here is the sample Spring boot application,

https://github.com/nkrishnakumarmca/RabbitMQ_FailureRetry

 

Reading property value as list

Suppose If we have comma separated value in properties we can use spring expression language to parse the as Java List as show below,

Sample property file:

Sample configuration for cluster nodes

redis.cluster.hosts=127.0.0.1:6358,172.x.y.z:6359,172.x.y.z:6360,172.x.y.z:6361

@Value(“#{T(java.util.Arrays).asList(‘${redis.cluster.hosts}’)}”)
private List<String> redisHosts;

Ref : https://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/expressions.html

Functional interfaces in Java 8

Interface Name Method(includes default & stattic) Description
Consumer<T> 1. void accept(T t)

2.default Consumer<T> andThen(Consumer<? super T> after)

Represents an operation that accepts a single input argument and returns no result.

Ex: String s -> System.out.println(“”)
BiConsumer<T, U> 1.  void accept(T t, U u)

2.  default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after)

 

Represents an operation that accepts two input arguments and returns no result.

Ex: (k,v) -> System.out.println(“k:” + k +” ,V “+ v )
Supplier<T> T get(); Opposite to consumer.Supplier of results.No input value but produces output.

Ex: () -> createLogMessage()
Function<T, R> 1. R apply(T t);

2.default <V> Function<V, R> compose(Function<? super V, ? extends T> before)

3.default <V> Function<T, V> andThen(Function<? super R, ? extends V> after)

4. static<T> Function<T, T> identity()

Represents a function that accepts one argument and produces a result.

Result can be same type or different.

Ex: Student s -> s.getName()
BiFunction<T, U, R> 1. R apply(T t, U u)

2. default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after)

Represents a function that accepts two arguments and produces a result.

Result can be same type or different.

UnaryOperator<T>

Extends Function<T, T>

static <T> UnaryOperator<T> identity() Represents an operation on a single operand that produces a result of the same type as its operand.

Ex: String s -> s.toLowerCase()
BinaryOperator<T>

Extends

BiFunction<T,T,T>

1.static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator)

2.static  <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator)

 

Represents an operation upon two operands of the same type, producing a result of the same type as the operands.

Ex: (String x, String y) -> { if(x.lengrth() > y.length())
     return x;
return y;
}
Predicate<T> 1.boolean test(T t);

2.default Predicate <T> and(Predicate<? super T> other)

3. default  Predicate<T> negate()

4.default  Predicate<T> or(Predicate<? super T> other)

5.Static <T> Predicate<T> isEqual(Object targetRef)

Represents a predicate (boolean-valued function) of one argument.

 

Ex: Student s-> s.getScore() == 80
BiPredicate<T, U> 1.boolean test(T t, U u);

2.default BiPredicate<T, U> and(BiPredicate<? super T, ? super U> other)

3.default  BiPredicate<T, U> negate()

4. default  BiPredicate<T, U> or(BiPredicate<? super T, ? super U> other)

Represents a predicate (boolean-valued function) of two arguments.

Ex: Files.find(start, maxDepth, (path,attr) -> String.valueOf(path).endsWith(“.js”) && attr.size() > 1024, FileVisitOption.FOLLOW_LINKS);

 

Java Client to connect to Active Directory(AD)

Requirement:

  1. Need to connect to ActiveDirector with SSL

  2. Retrive the user details from AD

  3. Update the password in AD.

Pre Req:

  1. LDAP url,port connuctivity(default ssl port :: 636, default port :: 389).

  2. User name and password.

  3. Certificate need to downloaded from LDAP machine, If you want to connecto over SSL.

Observations:

  1. LDAP URL may have space,comma,slash(\)

  2. You’ve to run the certificate generation client 2 times, Very first time you will get exception, Second time exception will not occurs(more…).

Implementation:

We are connecting to AD through SSL, So we need certificate. We can get the certificate from LDAP machine if you know the LDAP machine Ip,port and access to the machine from where you are downloading the certificate.

OpenSource code (InstallCert.java) to generate the certificate from the below link,

http://javarevisited.blogspot.in/2011/11/ldap-authentication-active-directory.html?_sm_au_=ijsFr74MLtVvN55k

import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;

public class TestAD {
 public static void main(String[] args) {
 LdapContext ctx = null;
 try {
 String existingPassword = "old@123";
 String newPassword = "test@123";
 boolean flag = false;
 //Location of the generated certificate
 System.setProperty("javax.net.ssl.trustStore", "/tmp/cert/jssecacerts");
 Hashtable&lt;String, Object&gt; env = new Hashtable&lt;String, Object&gt;();
 env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
 env.put(Context.SECURITY_AUTHENTICATION, "simple");
 env.put(Context.SECURITY_PRINCIPAL, "Raj, Kumar");
 // default HTTP port -389/ HTTPS -636
 env.put(Context.PROVIDER_URL, "LDAPS://127.0.0.1:636");
 env.put(Context.SECURITY_CREDENTIALS, existingPassword);
 env.put("java.naming.ldap.attributes.binary", "objectSID");
 env.put(Context.SECURITY_PROTOCOL, "ssl");
 ctx = new InitialLdapContext(env, null);
 new TestAD().fetch(ctx);
 if(flag) {
 ModificationItem[] mods = new ModificationItem[2];
 String oldQuotedPassword = "\"" + existingPassword + "\"";
 byte[] oldUnicodePassword = oldQuotedPassword.getBytes("UTF-16LE");
 String newQuotedPassword = "\"" + newPassword + "\"";
 byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");
 mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, new BasicAttribute("unicodePwd",
 oldUnicodePassword));
 mods[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute("unicodePwd",
 newUnicodePassword));
 ctx.modifyAttributes("CN=Raj\\, Kumar,OU=USERS,OU=NEW-YORK,DC=ATS,DC=org", mods);
 System.out.println("Password change completed....");
 ctx.close();
 }
 System.out.println("Process completed....");
 } catch (Exception e) {
 e.printStackTrace();
 }

 }

 public Attributes fetch(LdapContext ctx) {
 Attributes attributes = null;
 try {
 String path = "CN=Raj\\, kumar,OU=USERS,OU=NEW-YORK,DC=ATS,DC=org";
 System.out.println("AD url :: " + path);
 DirContext o = (DirContext) ctx.lookup(path);
 System.out.println("search done............................\n");
 attributes = o.getAttributes("");
 for (NamingEnumeration ae = attributes.getAll(); ae.hasMoreElements();) {
 Attribute attr = (Attribute) ae.next();
 String attrId = attr.getID();
 for (NamingEnumeration vals = attr.getAll(); vals.hasMore();) {
 String thing = vals.next().toString();
 System.out.println(attrId + " :::: " + thing);
 }
 }
 } catch (Exception e) {
 e.printStackTrace();
 System.exit(-1);
 }
 return attributes;
 }
}

Ref Links:

Possible Errors in AD

Redis client with custom Object

I came across a scenario where I need to write a Redis client and fetch the data from Redis server with custom Object as value.

This is the sample program to do my job.
Please add the Maven dependency to your pom.xml and add the below statement
<dependencies>

 <dependency>
 <groupId>redis.clients</groupId>
 <artifactId>jedis</artifactId>
 <version>2.8.0</version>
 </dependency>

 <dependency>
 <groupId>org.springframework.data</groupId>
 <artifactId>spring-data-redis</artifactId>
 <version>1.6.2.RELEASE</version>
 </dependency>

 <dependency>
 <groupId>org.apache.commons</groupId>
 <artifactId>commons-pool2</artifactId>
 <version>2.2</version>
 </dependency>
 
 <dependency>
 <groupId>org.springframework.data</groupId>
 <artifactId>spring-data-commons</artifactId>
 <version>1.5.0.RELEASE</version>
 </dependency>
 
 <dependency>
 <groupId>org.codehaus.jackson</groupId>
 <artifactId>jackson-mapper-asl</artifactId>
 <version>1.9.13</version>
 </dependency>

 </dependencies>

import java.io.Serializable;

import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JacksonJsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

public class RedisMain {

 public static void main(String[] args) {
 try {
 /**
 * Creating a connection factory to connect to redis server
 */
 JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
 /**
 * Provide the IP address where the Redis server is running
 */
 connectionFactory.setHostName(&quot;127.0.0.1&quot;);
 /**
 * Provide the port on which Redis server is running Default port :
 * 6379
 */
 connectionFactory.setPort(6379);
 /**
 * Which initializes the default values
 */
 connectionFactory.afterPropertiesSet();
 RedisTemplate&lt;String, Student&gt; redisTemplate = new RedisTemplate&lt;&gt;();
 redisTemplate.setConnectionFactory(connectionFactory);
 redisTemplate.afterPropertiesSet();
 /**
 * It is very important point to tell Redis server to store only
 * serialized key
 * 
 * Ref: &lt;a href=&quot;http://stackoverflow.com/questions/13215024/weird-redis-key-with-spring-data-jedis&quot;&gt;http://stackoverflow.com/questions/13215024/weird-redis-key-with-spring-data-jedis&lt;/a&gt;
 */
 redisTemplate.setKeySerializer(new StringRedisSerializer());
 redisTemplate.setValueSerializer(new JacksonJsonRedisSerializer&lt;Student&gt;(Student.class));
 /**
 * Saving a value to Redis
 */
 Student s = new Student(1, &quot;Student1&quot;);
 redisTemplate.opsForValue().set(&quot;kk&quot;, s);
 /**
 * Ex: kk is the key which is already store in Redis and we are
 * trying to fetch it.
 */
 Student tokenDetails = redisTemplate.opsForValue().get(&quot;kk&quot;);
 System.out.println(tokenDetails);

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

 private static class Student implements Serializable {

 private static final long serialVersionUID = 1L;
 private int id;
 private String name;

 public Student() {
 }

 public Student(int id, String name) {
 super();
 this.id = id;
 this.name = name;
 }

 /**
 * @return the id
 */
 public int getId() {
 return id;
 }

 /**
 * @param id
 * the id to set
 */
 public void setId(int id) {
 this.id = id;
 }

 /**
 * @return the name
 */
 public String getName() {
 return name;
 }

 /**
 * @param name
 * the name to set
 */
 public void setName(String name) {
 this.name = name;
 }

 @Override
 public String toString() {
 return &quot;Student [id=&quot; + id + &quot;, name=&quot; + name + &quot;]&quot;;
 }

 }
}

 

 

 

Enabling mod_jk in apache 2,tomcat and glassfish

Configuring Apache 2 and Tomcat flow the below links,

http://thetechnocratnotebook.blogspot.in/2012/05/installing-tomcat-7-and-apache2-with.html

Configuring the GlassFish execute the below commands and deploy a war file.

asadmin> create-network-listener --protocol http-listener-1 --listenerport 8009 --jkenabled true jk-connector
asadmin> set configs.config.server-config.network-config.network-listeners.network-listener.jk-connector.jk-enabled=true

 

Ref Link for Glass fish
https://docs.oracle.com/cd/E26576_01/doc.312/e24928/webapps.htm#GSADG00371
https://technology.amis.nl/2009/08/14/making-glassfish-v3-available-using-apache2-and-mod_jk/