• Sample code for encrypting and decrypting the given string

    
    [code language="java"]
    
    import org.apache.commons.codec.binary.Base64;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import javax.crypto.BadPaddingException;
    import javax.crypto.Cipher;
    import javax.crypto.IllegalBlockSizeException;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.PBEKeySpec;
    import javax.crypto.spec.PBEParameterSpec;
    import java.security.GeneralSecurityException;
    import java.security.Key;
    
    
    public class EncryptionUtil {
    
        private static final byte[] FIXED_SALT = "we!2$ef4gmoq!".getBytes();
        private static final BouncyCastleProvider BOUNCY_CASTLE_PROVIDER = new BouncyCastleProvider();
        private static final String ENCRYPT_DECRYPT_ALGORITHM = "PBEWITHSHA256AND256BITAES-CBC-BC";
        private static final String ALGORITHM_WITH_PADDING = "AES/CBC/PKCS7Padding";
        private static final String KEY = "test";
        private static final int ITERATION_COUNT = 100000;
    
        public static String decrypt(String encrypted) {
            try {
                byte[] accountIdByteArray = org.apache.commons.codec.binary.Base64.decodeBase64(encrypted);
                return new String(cipher(Cipher.DECRYPT_MODE, KEY).doFinal(accountIdByteArray));
            } catch (IllegalBlockSizeException | BadPaddingException e) {
                throw new RuntimeException("Exception occurred in decryption.", e);
            }
        }
    
        public static String encrypt(String value) {
            try {
                return Base64.encodeBase64URLSafeString(cipher(Cipher.ENCRYPT_MODE, KEY).doFinal(value.getBytes()));
            } catch (IllegalBlockSizeException | BadPaddingException e) {
                throw new RuntimeException("Exception occurred in encryption.", e);
            }
        }
    
        private static Cipher cipher(int mode, String key) {
            try {
                Cipher cipher = Cipher.getInstance(ALGORITHM_WITH_PADDING, BOUNCY_CASTLE_PROVIDER);
                SecretKeyFactory factory = SecretKeyFactory.getInstance(ENCRYPT_DECRYPT_ALGORITHM, BOUNCY_CASTLE_PROVIDER);
                PBEKeySpec keySpec = new PBEKeySpec(key.toCharArray(), FIXED_SALT, ITERATION_COUNT);
                Key secretKey = factory.generateSecret(keySpec);
                PBEParameterSpec parameter = new PBEParameterSpec(FIXED_SALT, ITERATION_COUNT);
                cipher.init(mode, secretKey, parameter);
                return cipher;
            } catch (GeneralSecurityException e) {
                throw new RuntimeException("Exception occurred in cipher init ", e);
            }
    
        }
    
    }
    
    [/code]
  • Link to install azure cli on MAC

    https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-macos?view=azure-cli-latest

    After completing the steps in this doc, run the below command to link the Azure and local terminal

    brew update && brew install azure-cli

    az login

    It will open a browser and provide user name and password, then you will be connected

    To make kubectl to work run the below command

    az aks get-credentials –resource-group case-study –name caststudy-cluster

    Give correct name highlighted in green colour.

    To enable dashboard:

    kubectl describe secret admin-user-token-nbcdm -n kube-system – To get the token

    Follow the steps in youtube https://www.youtube.com/watch?v=aB0TagEzTAw

    https://github.com/kubernetes/dashboard

    kubectl apply -f https://gist.github.com/chukaofili/9e94d966e73566eba5abdca7ccb067e6#file-k8s-dashboard-admin-user-yaml

    http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#/overview?namespace=default

  • Docker Commands

    Building docker image from DockerFile

    mvn clean install

    docker build -t kk-spring-boot-hello .

    Build and push the image to https://hub.docker.com/

    docker run -p 8080:8080 kk-spring-boot-hello

    docker login

    To push particular tag version:

    docker tag 71ba6b7eadf8 nkrishnakumar/kk-spring-boot-hello:v1.0

    docker push nkrishnakumar/kk-spring-boot-hello:v1.0

    To Push to latest version:

    docker push nkrishnakumar/kk-spring-boot-hello

    Install and configure minikube:

    Link for download

    https://kubernetes.io/docs/setup/learning-environment/minikube/

    https://kubernetes.io/docs/tasks/tools/install-minikube/

    Command to run minikube in loacal with docker hub

     minikube start --driver=docker

    Start the cluster, by running the minikube start command:

    minikube start –wait=false

    Run kubernetes :
    kubectl apply -f springboot-deployment.yml
    kubectl apply -f springboot-svc.yml
    kubectl get services --all-namespaces
    kubectl expose deployment rollout-deployment --type=NodePort --port=8080
    kubectl port-forward deployment/rollout-deployment 8080:8081
    minikube service kk-spring-boot-hello --url
    
    Roll out and Roll Back:
    kubectl rollout history deployment.app/rollout-deployment
    kubectl rollout undo deployment.app/rollout-deployment --to-revision=8
    
    Kubectl get events —sort-by=.metadata.creationTime
    Kubectl get rs -o wide
    Kubectl set image deployment <deployment_name> <container_name>=<image_with_tag_name> --record=true
    kubectl logs <podname>
    
    Kubectl expose deployment <deployment-name> —type=LoadBalancer —port=8080

    Install and configure MongoDB, mysql, Kafka on MAC

    brew tap mongodb/brew
    brew install mongodb-community@4.0 
    brew services start mongodb-community@4.0
    
    brew install mysql
    mysql_secure_installation
    brew services start mysql
    mysql -u root -p Root@123
    Ref Link: https://flaviocopes.com/mysql-how-to-install/
    
    
    brew install redis
    brew services start redis
    
    brew install kafka
    zookeeper-server-start /usr/local/etc/kafka/zookeeper.properties
    
    kafka-server-start  /usr/local/etc/kafka/server.properties
    

    Login into Docker:

     docker ps – Gives the container details

     docker exec -it 9b5c325b99d8 bash – To login into the container

    Connecting to Redis in k8s

     kubectl exec -it <pod name> -n <namespace> — redis-cli

    kubectl exec -it mongodb-standalone-0 bash

    Delete docker tag with none
    docker images | grep none | awk '{ print $3; }' | xargs docker rmi
    

    kubectl config set-context –current –namespace kk

    Istio

    istioctl analyze –all-namespaces

  • 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();
    }
    
    
  • 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.
  • 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;
    }
    
    
  • Step 1 : Install the aws cli in your machine
    Step 2 : Open commnad prompt and type aws configure
    Ex: default configuration
    C:>aws configure
    AWS Access Key ID [None]: foo
    AWS Secret Access Key [None]: bar
    Default region name [None]: us-east-1
    Default output format [None]:

    Now configuration is completed.

    AWS cli commands:

    Command to create table pointing to local DynamoDB

    aws –endpoint-url=http://localhost:8000 dynamodb –region=us-east-1 create-table –cli-input-json file://employee.json

    Command delete table
    aws dynamodb delete-table –table-name employee

    Ref: https://cloudacademy.com/blog/amazon-dynamodb-ten-things/

  • 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

     

  • 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

Design a site like this with WordPress.com
Get started