Monday, August 31, 2020

keystore javax.net.ssl.keyStore in Spring or Spring boot

TLS 2 connection between Spring boot client and server.  SSL configuration class inside your client application to setup keystore (.jks ). .jks file needs to be inside  your classpath (resource folder) of spring application.

import java.io.FileNotFoundException;

import javax.annotation.PostConstruct;

import org.springframework.context.annotation.Configuration;

import org.springframework.util.ResourceUtils;


@Configuration

public class TLSConfig {


@PostConstruct

private void configureTLS() throws FileNotFoundException {


String filePath = ResourceUtils.getFile("classpath:filejks.jks").getPath();

System.setProperty("https.protocols", "TLSv1.2");

System.setProperty("javax.net.ssl.keyStore", filePath);

System.setProperty("javax.net.ssl.keyStorePassword", "password");

}


Read .jks file from spring boot jar file

InputStream inputStream = null;
File jksFile = null;
try {
ClassPathResource classPathResource = new ClassPathResource("jksfilename.jks");
inputStream = classPathResource.getInputStream();
jksFile = File.createTempFile("anyfilename", ".jks");
java.nio.file.Files.copy(inputStream, jksFile.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
inputStream.close();
}

System.setProperty("javax.net.ssl.keyStore", jksFile.getPath());

Labels:

Monday, August 24, 2020

Maintain ordering in ActiveMQ with Multiple consumer - Exclusive consumer

 

Exclusive consumer - ActiveMQ Embedded

If you have multiple MessageConsumer consuming from same queue irrespective of same JVM or not. Then the order of processing of  queue object can not guarantee.
In order to maintain the order in which object inserted 'Exclusive consumer' needed.
The broker will pick a single MessageConsumer to get all the messages for a queue to ensure ordering. If that consumer fails, the broker will auto failover and choose another consumer

In order to make Exclusive consumer, we can make consumer is exclusive or not,  when defining queue name

public static final String data_queue = "data-queue?consumer.exclusive=true";

Labels: ,

Schedule or delay a message ActiveMQ - Spring boot Embedded broker

Embedded broker scheduler (delay a message) ActiveMQ Spring boot

Let take a scenario where we are simultaneously pushing data into message queue and database and my expectation is first it updates database and then message consumer  consume data (after some delay).
We can achieve this by scheduling the ActiveMQ or we can say schedule the delivery of message.
By default 'Scheduler' is not enabled and we need enable it manually and also we need local persistent to store messages.

Below are the steps to configure scheduler (or delay  messages ) in ActiveMQ (Embedded)

1.    Add the following dependencies in pom.xml

        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-kahadb-store</artifactId>
            <scope>runtime</scope>
        </dependency>

2.    Enable broker persistent and scheduler support.
 
vm://embedded?broker.persistent=true&broker.useShutdownHook=false&broker.schedulerSupport=true


3. Add the delay time in millisecond inside message sender

public void sendToQue(MessageQueDTO myMessage) {

        jmsTemplate.convertAndSend(message_que, myMessage,m -> {

            m.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, 100000);

            return m;

         }); 




Labels: , , , , ,

Sunday, August 16, 2020

Spring boot JMS template Embedded ActiveMQ

Embedded ActiveMQ

When you deploy broker in same JVM. This will help you avoid network hop, load balancing and other network issue.
Spring boot provides you support to create embedded ActiveMQ.

Steps to configure embedded broker ActiveMQ with spring boot

1.    Maven dependency

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-broker</artifactId>
</dependency>

2. Properties file configuration  JMS & ActiveMQ

 Inside application.properties file we can provide JMS & ActiveMQ configuration.We also need to provide broker url.

spring.jms.listener.acknowledge-mode=auto
spring.jms.listener.auto-startup=true
spring.jms.listener.concurrency=5
spring.jms.listener.max-concurrency=10
spring.jms.pub-sub-domain=false
spring.jms.template.default-destination=empty
spring.jms.template.priority=100
spring.jms.template.qos-enabled=true
spring.jms.template.receive-timeout=100000000
spring.jms.template.time-to-live=36000000

spring.activemq.broker-url=vm://embedded?broker.persistent=false&broker.useShutdownHook=false
spring.activemq.close-timeout=15000
spring.activemq.in-memory=true
spring.activemq.non-blocking-redelivery=false
spring.activemq.password=
spring.activemq.user=
spring.activemq.send-timeout=0
spring.activemq.packages.trust-all=false
spring.activemq.packages.trusted=
spring.activemq.pool.block-if-full=true
spring.activemq.pool.block-if-full-timeout=-1
spring.activemq.pool.create-connection-on-startup=true
spring.activemq.pool.enabled=false
spring.activemq.pool.expiry-timeout=0
spring.activemq.pool.idle-timeout=30000
spring.activemq.pool.max-connections=1
spring.activemq.pool.maximum-active-session-per-connection=500
spring.activemq.pool.reconnect-on-exception=true
spring.activemq.pool.time-between-expiration-check=-1
spring.activemq.pool.use-anonymous-producers=true

3. Configuration class 

 Inside your configuration class we need to provide the bean configuration for JMS

@EnableJms
@Configuration
public class ApplicationConfiguration{
   
    @Bean
    public JmsListenerContainerFactory<?> queueListenerFactory() {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setMessageConverter(messageConverter());
        return factory;
    }

    @Bean
    public MessageConverter messageConverter() {
        MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
        converter.setTargetType(MessageType.TEXT);
        converter.setTypeIdPropertyName("_type");
        return converter;
    }

4. Define que name as constant    

We can define que name as constant in any Java class (ApplicationConstants.java)

public static final String messageQue = "message-que";

5. Message receiver class    

Create a message receiver ( a JmsListener class)

@JmsListener(destination = messageQue )
public void messageReceiver(@Payload MessageData data, @Headers MessageHeaders headers, Message message,
Session session) {
//// your code will go here
}

MessageData : This will the object that you will send to message, this can be String or any other object of your choice.
destination = messageQue : This will be que name , we can choose any que name and sender will send data to the following que.

6. Message sender class 

Create a message sender

Create an object of JmsTemplate and using this object we can send the desired message to que.

The implementation will be as follows :

@Service
public class MessageSender {

    @Autowired
    private JmsTemplate jmsTemplate;
    
    public void sendToQue(MessageData message) {
        jmsTemplate.convertAndSend(messageQue, message,m -> {
            return m;
         });
    }


Now we are done with the configuration and you can send the data from your service class using the method sendToQue of  MessageSender class.


Labels: , , , , , , , ,

Wednesday, August 12, 2020

Optimistic Vs Pessimistic lock

When you need a lock ?

Let's take an example in any web application where two user simultaneous read the record and both are trying to update the record inside the database in that case last user will win and it will override the first user data. In this case first user data will be lost without any warning / exception.

So to deal with this kind of situation we need 'lock mechanism' .

Optimistic lock:

Optimistic lock don't lock the table while reading so in above example both users can simultaneously read the record but while updating it will check the conflict like if user A first updated the record and then user B try to update the record with their version then application will throw exception. In this case user B need to read again latest record and then can update.

How to implement 'optimistic' lock ?

JPA / Hibernate we can use the concept of 'version'. Inside the entity you need to define version attribute in the following manner.

@Version
private int version;

So when hibernate execute the 'update' query for the entity it will apply version in where clause
in following manner

where version=?
version will contain the old value that entity received while reading if it don't match
at the time of update transaction will fail.

Pessimistic lock:

Pessimistic locking mechanism will be used to prevent the simultaneous update of the record. It is an exclusive lock so that no one else can start modifies the record. The record will be locked as soon as it accessed. In above example if user A start read the record
it will lock the record in table, this will block the other user to read the data as well.

How to implement 'pessimistic' lock using JPA?

Using JPA we can implement pessimistic lock.

LockModeType.PESSIMISTIC_READ and LockModeType.PESSIMISTIC_WRITE


LockModeType.PESSIMISTIC_READ: When you want to read the entity only.

EntityManager entityManager = entityManagerFactory.createEntityManager(); entityManager.getTransaction().begin(); User user = entityManager.find(User.class, 10L, LockModeType.PESSIMISTIC_READ);


LockModeType.PESSIMISTIC_WRITE : When your transaction can update the entity. It is an
exclusive lock prevent other transaction from acquiring READ or WRITE.


EntityManager entityManager = entityManagerFactory.createEntityManager(); entityManager.getTransaction().begin(); User user = entityManger.find(User.class, 10L, LockModeType.PESSIMISTIC_WRITE);








Labels: , , , , , ,

Thursday, August 6, 2020

Java Array Vs ArrayList Vs LinkedList

ArrayList is ordered collection, out of the box not synchronized. You can synchronize externally.

ArrayList is slower than Array. Use Array when you know the size of element.

ArrayList uses Array internally. When you perform add on ArrayList it creates a new Array with n+1 dimension and older element will be copied to first n elements and last n+1 will be filled with new value provided in add function.

LinkedList  is more convenient to use and let you add, remove  element from both side of collection.LinkedList do not use Array. LinkedList is a sequence of nodes. Node contains header & pointer. Header contains object and pointer contains address of next node.

Sunday, August 2, 2020

Spring scheduler lock Shedlock

Spring boot scheduler in clustered environment

Let's take an example suppose your application has as feature in which it has scheduler which runs on some predefined time interval and send an email to some concerned person.
And suppose your  application has two instances running. In that case two different instance will send mail and mail will send twice to particular person.
So to restrict this you need to apply some mechanism so that if one instance is running the scheduler at that moment second instance will not run it again. To achieve this you need to apply lock (Scheduler lock).

For this we have Java library 'Shedlock'.

1.    Add the following dependency inside pom.xml
    
       <dependency>
        <groupId>net.javacrumbs.shedlock</groupId>
        <artifactId>shedlock-spring</artifactId>
        <version>2.1.0</version>
    </dependency>
    <dependency>
        <groupId>net.javacrumbs.shedlock</groupId>
        <artifactId>shedlock-provider-jdbc-template</artifactId>
        <version>2.1.0</version>
    </dependency>

2.    Shedlock use external storage like JDBC database or other storage.
In our case we have used MySQL database, In this case we also need to create a 'table shedlock'

    CREATE TABLE shedlock(name VARCHAR(64) NOT NULL, lock_until TIMESTAMP(3) NOT NULL, locked_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), locked_by VARCHAR(255) NOT NULL, PRIMARY KEY (name));

3.    Now we need to create a config class for configuring shedlock

        @EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
        @Configuration
public class ShedLockConfig {
    
    @Bean
    public LockProvider lockProvider(DataSource dataSource) {
        return new JdbcTemplateLockProvider(dataSource, "shedlock");
    }

    @Bean
    public ScheduledLockConfiguration scheduledLockConfiguration(LockProvider lockProvider) {
        return ScheduledLockConfigurationBuilder
                .withLockProvider(lockProvider)
                .withPoolSize(10)
                .withDefaultLockAtMostFor(Duration.ofMinutes(10))
                .build();
    }

4.  Now apply annotation @SchedulerLock along with your @Scheduled annotation of Scheduler class     in the following manner
 
     @SchedulerLock(name = "nameTest", lockAtMostFor = TEN_MIN, lockAtLeastFor =         TEN_MIN)

And you are Done !

Note :  Please make sure that both of your node running in same time zone and synchronized.
             

Labels: , , , ,