Message durability in RabbitMQ

Server : Consumer

public class Main {

    public static void main(String[] args) throws IOException, TimeoutException {
        String queueName = "queue2";

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");

        Connection connection = factory.newConnection();

        Channel channel = connection.createChannel();

        channel.queueDeclare(queueName, true, false, false, null);
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        channel.basicQos(1);

        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message=new String(body,"UTF-8");

                try {
                    doWork(message);
                }
                catch (Exception ex)
                {
                    ex.printStackTrace();
                }
                finally {
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };

        channel.basicConsume(queueName,false,consumer);
    }

    public static void doWork(String message) throws InterruptedException {
        System.out.println(" [x] Received '" + message + "'");

        int sleepTime=new Random().nextInt(2000);

        Thread.sleep(sleepTime);
    }
}

Client : Producer

public class Main {

    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {

        String queueName = "queue2";

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");

        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        channel.queueDeclare(queueName, true, false, false, null);

        int count = 0;

        while (count < 100) {

            Date date = new Date();

            String message = String.format("%d : %s", count, date.toString());

            channel.basicPublish("", queueName, MessageProperties.PERSISTENT_TEXT_PLAIN,
                    message.getBytes("UTF-8"));
            System.out.println(String.format(" [x] Sent %s", message));

            Thread.sleep(1000);
            count++;
        }
    }
}

References
https://pupli.net/2017/07/16/work-queues-sample-in-rabbitmq/
https://www.rabbitmq.com/tutorials/tutorial-two-java.html

Work Queues Sample in RabbitMQ

Server : Consumer

public class Main {

    public static void main(String[] args) throws IOException, TimeoutException {
        String queueName = "queue2";

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");

        Connection connection = factory.newConnection();

        Channel channel = connection.createChannel();

        channel.queueDeclare(queueName, true, false, false, null);
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        channel.basicQos(1);

        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message=new String(body,"UTF-8");

                try {
                    doWork(message);
                }
                catch (Exception ex)
                {
                    ex.printStackTrace();
                }
                finally {
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };

        channel.basicConsume(queueName,false,consumer);
    }

    public static void doWork(String message) throws InterruptedException {
        System.out.println(" [x] Received '" + message + "'");

        int sleepTime=new Random().nextInt(2000);

        Thread.sleep(sleepTime);
    }
}

Client : Producer

public class Main {

    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {

        String queueName = "queue2";

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");

        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        channel.queueDeclare(queueName, true, false, false, null);

        int count = 0;

        while (count < 100) {

            Date date = new Date();

            String message = String.format("%d : %s", count, date.toString());

            channel.basicPublish("", queueName, MessageProperties.PERSISTENT_TEXT_PLAIN,
                    message.getBytes("UTF-8"));
            System.out.println(String.format(" [x] Sent %s", message));

            Thread.sleep(1000);
            count++;
        }
    }
}

References
https://www.rabbitmq.com/tutorials/tutorial-two-java.html
https://github.com/mhdr/RabbitMQSamples/tree/master/002_WorkQueues

Hello World Sample in RabbitMQ

Server

public class Main {

    public static void main(String[] args) throws IOException, TimeoutException {
        String queueName="Hello";

        ConnectionFactory factory=new ConnectionFactory();
        factory.setHost("localhost");

        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        channel.queueDeclare(queueName,false,false,false,null);

        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");


        Consumer consumer=new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {

                String message=new String(body,"UTF-8");
                System.out.println(" [x] Received '" + message + "'");
            }
        };

        channel.basicConsume(queueName,true,consumer);
    }
}

Client

public class Main {
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {

        String queueName="Hello";

        ConnectionFactory factory=new ConnectionFactory();
        factory.setHost("localhost");

        Connection connection= factory.newConnection();
        Channel channel= connection.createChannel();

        channel.queueDeclare(queueName,false,false,false,null);


        int count=0;

        while (count<100){
            Date date=new Date();
            String message=String.format("Hello World : %s", date.toString());

            channel.basicPublish("",queueName,null,message.getBytes("UTF-8"));

            System.out.println(" [x] Sent '" + message + "'");
            count++;

            Thread.sleep(1000);
        }

        channel.close();
        connection.close();
    }
}

References
https://www.rabbitmq.com/tutorials/tutorial-one-java.html
https://github.com/mhdr/RabbitMQSamples/tree/master/001_HelloWorld

Install Spring Boot applications

Make fully executable applications for Unix systems
A fully executable jar can be executed like any other executable binary or it can be registered with init.d or systemd
Gradle configuration:

bootJar {
  launchScript()
}

Installation as a systemd Service

create a script named myapp.service and place it in /etc/systemd/system directory

[Unit]
Description=myapp
After=syslog.target

[Service]
User=myapp
ExecStart=/var/myapp/myapp.jar
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target

Remember to change the DescriptionUser, and ExecStart fields for your application.

To flag the application to start automatically on system boot, use the following command:

systemctl enable myapp.service

References
https://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/sect-managing_services_with_systemd-unit_files
https://tecadmin.net/setup-autorun-python-script-using-systemd/
https://www.raspberrypi-spy.co.uk/2015/10/how-to-autorun-a-python-script-on-boot-using-systemd/

Configure Spring Session with Redis

build.gradle

compile('org.springframework.session:spring-session')
compile('org.springframework.boot:spring-boot-starter-data-redis')

application.properties

spring.session.store-type=redis

spring.redis.host=localhost
#spring.redis.password=secret
spring.redis.port=6379

Receive JSON data in Spring Boot MVC Controller

FormsApiController.java

@RequestMapping(value = "/api/form/saveForm", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public Map saveForm(HttpServletRequest request, HttpServletResponse response, @RequestBody String payload) {
        SessionManager sessionManager = new SessionManager(request, response);

        Map result = null;

        FormBL formBL = new FormBL(request, response);
        result = formBL.saveForm(payload);

        return result;
    }

FormBL.java

    public Map<String, Object> saveForm(String payload) {
        Map<String, Object> result = new HashMap<>();

        try {

            Gson gson = new Gson();
            PojoForm pojoForm = gson.fromJson(payload, PojoForm.class);

            Form form = new Form();
            if (pojoForm.formId > 0) {
                form.id = pojoForm.formId;
            }


            Machinery machinery = null;

            if (pojoForm.machineryId > 0) {
                machinery = Statics.machineryRepository.findById(pojoForm.machineryId);
            }

            form.name = pojoForm.formName;
            form.machinery = machinery;

            Form dbForm = Statics.formRepository.save(form);
            pojoForm.formId = dbForm.id;

            if (pojoForm.formRows.size() > 0) {
                for (PojoFormRow row : pojoForm.formRows) {
                    FormRow formRow = new FormRow();

                    if (row.getId() > 0) {
                        formRow.id = row.getId();
                    }

                    formRow.rowOrder = row.row_order;
                    formRow.rowType = row.getRowType();
                    formRow.title = row.getTitle();
                    formRow.form = dbForm;

                    FormRow dbFormRow = Statics.formRowRepository.save(formRow);
                    row.id = dbFormRow.id;

                    if (row.getRow_values().size() > 0) {
                        for (PojoRowValue rowValue : row.getRow_values()) {
                            RowSelectValue rowSelectValue = new RowSelectValue();

                            if (rowValue.getId() > 0) {
                                rowSelectValue.id = rowValue.getId();
                            }

                            rowSelectValue.title = rowValue.title;
                            rowSelectValue.titleOrder = rowValue.title_order;
                            rowSelectValue.formRow = dbFormRow;

                            RowSelectValue dbRowSelectValue = Statics.rowSelectValueRepository.save(rowSelectValue);
                            rowValue.id = dbRowSelectValue.id;
                        }
                    }
                }
            }

            result.put("form", "");
            result.put("error", 0);
        } catch (Exception ex) {
            // exception
            result.put("error", 1);
            ex.printStackTrace();
        }

        return result;
    }

Read XML from URL in Android

Read XML file :

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new URL(url).openStream());

Parse :

File fXmlFile = new File("/Users/mkyong/staff.xml");
	DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
	DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
	Document doc = dBuilder.parse(fXmlFile);

	//optional, but recommended
	//read this - http://stackoverflow.com/questions/13786607/normalization-in-dom-parsing-with-java-how-does-it-work
	doc.getDocumentElement().normalize();

	System.out.println("Root element :" + doc.getDocumentElement().getNodeName());

	NodeList nList = doc.getElementsByTagName("staff");

	System.out.println("----------------------------");

	for (int temp = 0; temp < nList.getLength(); temp++) {

		Node nNode = nList.item(temp);

		System.out.println("\nCurrent Element :" + nNode.getNodeName());

		if (nNode.getNodeType() == Node.ELEMENT_NODE) {

			Element eElement = (Element) nNode;

			System.out.println("Staff id : " + eElement.getAttribute("id"));
			System.out.println("First Name : " + eElement.getElementsByTagName("firstname").item(0).getTextContent());
			System.out.println("Last Name : " + eElement.getElementsByTagName("lastname").item(0).getTextContent());
			System.out.println("Nick Name : " + eElement.getElementsByTagName("nickname").item(0).getTextContent());
			System.out.println("Salary : " + eElement.getElementsByTagName("salary").item(0).getTextContent());

		}

References
https://stackoverflow.com/questions/16958081/java-how-to-read-xml-from-url
https://www.mkyong.com/java/how-to-read-xml-file-in-java-dom-parser/

Create an Index using JPA

@Entity
@Table(name = "region",
       indexes = {@Index(name = "my_index_name",  columnList="iso_code", unique = true),
                  @Index(name = "my_index_name2", columnList="name",     unique = false)})
public class Region{

    @Column(name = "iso_code", nullable = false)
    private String isoCode;

    @Column(name = "name", nullable = false)
    private String name;

} 

or

@Entity
@Table(name    = "company__activity", 
       indexes = {@Index(name = "i_company_activity", columnList = "activity_id,company_id")})
public class CompanyActivity{

References
http://stackoverflow.com/questions/3405229/specifying-an-index-non-unique-key-using-jpa

Java 8 Stream Examples

public class Java8Tester {
   public static void main(String args[]){
      System.out.println("Using Java 7: ");
    
      // Count empty strings
      List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
      System.out.println("List: " +strings);
      long count = getCountEmptyStringUsingJava7(strings);
    
      System.out.println("Empty Strings: " + count);
      count = getCountLength3UsingJava7(strings);
    
      System.out.println("Strings of length 3: " + count);
    
      //Eliminate empty string
      List<String> filtered = deleteEmptyStringsUsingJava7(strings);
      System.out.println("Filtered List: " + filtered);
    
      //Eliminate empty string and join using comma.
      String mergedString = getMergedStringUsingJava7(strings,", ");
      System.out.println("Merged String: " + mergedString);
      List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
    
      //get list of square of distinct numbers
      List<Integer> squaresList = getSquares(numbers);
      System.out.println("Squares List: " + squaresList);
      List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19);
    
      System.out.println("List: " +integers);
      System.out.println("Highest number in List : " + getMax(integers));
      System.out.println("Lowest number in List : " + getMin(integers));
      System.out.println("Sum of all numbers : " + getSum(integers));
      System.out.println("Average of all numbers : " + getAverage(integers));
      System.out.println("Random Numbers: ");
    
      //print ten random numbers
      Random random = new Random();
    
      for(int i=0; i < 10; i++){
         System.out.println(random.nextInt());
      }
    
      System.out.println("Using Java 8: ");
      System.out.println("List: " +strings);
    
      count = strings.stream().filter(string->string.isEmpty()).count();
      System.out.println("Empty Strings: " + count);
    
      count = strings.stream().filter(string -> string.length() == 3).count();
      System.out.println("Strings of length 3: " + count);
    
      filtered = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.toList());
      System.out.println("Filtered List: " + filtered);
    
      mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", "));
      System.out.println("Merged String: " + mergedString);
    
      squaresList = numbers.stream().map( i ->i*i).distinct().collect(Collectors.toList());
      System.out.println("Squares List: " + squaresList);
      System.out.println("List: " +integers);
    
      IntSummaryStatistics stats = integers.stream().mapToInt((x) ->x).summaryStatistics();
    
      System.out.println("Highest number in List : " + stats.getMax());
      System.out.println("Lowest number in List : " + stats.getMin());
      System.out.println("Sum of all numbers : " + stats.getSum());
      System.out.println("Average of all numbers : " + stats.getAverage());
      System.out.println("Random Numbers: ");
    
      random.ints().limit(10).sorted().forEach(System.out::println);
    
      //parallel processing
      count = strings.parallelStream().filter(string -> string.isEmpty()).count();
      System.out.println("Empty Strings: " + count);
   }
  
   private static int getCountEmptyStringUsingJava7(List<String> strings){
      int count = 0;
    
      for(String string: strings){
    
         if(string.isEmpty()){
            count++;
         }
      }
      return count;
   }
  
   private static int getCountLength3UsingJava7(List<String> strings){
      int count = 0;
    
      for(String string: strings){
    
         if(string.length() == 3){
            count++;
         }
      }
      return count;
   }
  
   private static List<String> deleteEmptyStringsUsingJava7(List<String> strings){
      List<String> filteredList = new ArrayList<String>();
    
      for(String string: strings){
    
         if(!string.isEmpty()){
             filteredList.add(string);
         }
      }
      return filteredList;
   }
  
   private static String getMergedStringUsingJava7(List<String> strings, String separator){
      StringBuilder stringBuilder = new StringBuilder();
    
      for(String string: strings){
    
         if(!string.isEmpty()){
            stringBuilder.append(string);
            stringBuilder.append(separator);
         }
      }
      String mergedString = stringBuilder.toString();
      return mergedString.substring(0, mergedString.length()-2);
   }
  
   private static List<Integer> getSquares(List<Integer> numbers){
      List<Integer> squaresList = new ArrayList<Integer>();
    
      for(Integer number: numbers){
         Integer square = new Integer(number.intValue() * number.intValue());
      
         if(!squaresList.contains(square)){
            squaresList.add(square);
         }
      }
      return squaresList;
   }
  
   private static int getMax(List<Integer> numbers){
      int max = numbers.get(0);
    
      for(int i=1;i < numbers.size();i++){
    
         Integer number = numbers.get(i);
      
         if(number.intValue() > max){
            max = number.intValue();
         }
      }
      return max;
   }
  
   private static int getMin(List<Integer> numbers){
      int min = numbers.get(0);
    
      for(int i=1;i < numbers.size();i++){
         Integer number = numbers.get(i);
    
         if(number.intValue() < min){
            min = number.intValue();
         }
      }
      return min;
   }
  
   private static int getSum(List numbers){
      int sum = (int)(numbers.get(0));
    
      for(int i=1;i < numbers.size();i++){
         sum += (int)numbers.get(i);
      }
      return sum;
   }
  
   private static int getAverage(List<Integer> numbers){
      return getSum(numbers) / numbers.size();
   }
}

 

References
https://www.tutorialspoint.com/java8/java8_streams.htm
http://www.drdobbs.com/jvm/lambdas-and-streams-in-java-8-libraries/240166818

How to Configure Spring Session with JDBC for MySQL

build.gradle

buildscript {
	ext {
		springBootVersion = '1.5.2.RELEASE'
	}
	repositories {
		mavenCentral()
	}
	dependencies {
		classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
	}
}

apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'org.springframework.boot'

jar {
	baseName = 'logbook-server'
	version = '0.0.1-SNAPSHOT'
}

sourceCompatibility = 1.8

repositories {
	mavenCentral()
}


dependencies {
	compile('org.springframework.boot:spring-boot-starter-data-jpa')
	compile('org.springframework.session:spring-session')
	compile('org.springframework.boot:spring-boot-starter-thymeleaf')
	compile('org.springframework.boot:spring-boot-starter-web')
	compile('org.springframework.boot:spring-boot-starter-web-services')
	compile('org.springframework.boot:spring-boot-starter-websocket')
	runtime('org.springframework.boot:spring-boot-devtools')
	runtime('mysql:mysql-connector-java')
	compileOnly('org.springframework.boot:spring-boot-configuration-processor')
	compileOnly('org.projectlombok:lombok')
	testCompile('org.springframework.boot:spring-boot-starter-test')

	// https://mvnrepository.com/artifact/joda-time/joda-time
	compile group: 'joda-time', name: 'joda-time', version: '2.9.7'

	// https://mvnrepository.com/artifact/net.time4j/time4j-parent
	compile group: 'net.time4j', name: 'time4j-parent', version: '4.25'

	// https://mvnrepository.com/artifact/org.apache.commons/commons-lang3
	compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.5'

	// https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on
	compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.56'

	// https://mvnrepository.com/artifact/com.google.code.gson/gson
	compile group: 'com.google.code.gson', name: 'gson', version: '2.8.0'

	// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-tomcat
	compile group: 'org.springframework.boot', name: 'spring-boot-starter-tomcat'

	// https://mvnrepository.com/artifact/commons-io/commons-io
	compile group: 'commons-io', name: 'commons-io', version: '2.5'
}

application.properties

server.port=13602
spring.session.store-type=jdbc
server.compression.enabled=true
server.use-forward-headers=true
server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain,text/css,application/javascript
logging.file=logbook-server.log
spring.datasource.url=jdbc:mysql://localhost/logbook
spring.datasource.username=root
spring.datasource.password=12345
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

# Number of ms to wait before throwing an exception if no connection is available.
spring.datasource.tomcat.max-wait=10000

# Maximum number of active connections that can be allocated from this pool at the same time.
spring.datasource.tomcat.max-active=50

# Validate the connection before borrowing it from the pool.
spring.datasource.tomcat.test-on-borrow=true

spring.jpa.hibernate.ddl-auto=create

HttpSessionConfig.java

@Configuration
@EnableJdbcHttpSession
public class HttpSessionConfig {

}

then execute this script on MySQL

CREATE TABLE SPRING_SESSION (
        SESSION_ID CHAR(36),
        CREATION_TIME BIGINT NOT NULL,
        LAST_ACCESS_TIME BIGINT NOT NULL,
        MAX_INACTIVE_INTERVAL INT NOT NULL,
        PRINCIPAL_NAME VARCHAR(100),
        CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID)
) ENGINE=InnoDB;

CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);

CREATE TABLE SPRING_SESSION_ATTRIBUTES (
        SESSION_ID CHAR(36),
        ATTRIBUTE_NAME VARCHAR(200),
        ATTRIBUTE_BYTES BLOB,
        CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
        CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE
) ENGINE=InnoDB;

CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID);

References
http://docs.spring.io/spring-session/docs/current/reference/html5/#api-jdbcoperationssessionrepository-storage
http://stackoverflow.com/questions/37398905/spring-session-with-jdbc-configuration-table-test-spring-session-doesnt-exis