Monday, February 20, 2017

Java Sequence Generator which simulates Oracle DB Sequence Generator

There is a requirement in my recent project, to generate 11 digit long sequence number without any database. Interesting, we are so used to rely on database to generate sequence number. In Java programming world, there isn’t a convenient library to generate sequence number!?

Solution 1: UUID.randomUUID().
UUID is alpha numeric and UUID size is way bigger than 11 digits.

Solution 2: System.currentTimeMillis().
[1] System.currentTimeMillis() generates 13 digits.
[2] If we substring the left most 11 characters, we lose the accuracy.
[3] The sequence is not continuous.
[4] In the very fast machine and fast retrieval, it is possible to obtain repeated value.

Solution 3: System.currentTimeMillis() as init value and +1 subsequently.
In the high volume retrieval, +1 may outrun the speed of time, e.g. 20000 transactions per second. When program restart, the newly System.currentTimeMillis() init value might have been used previously.

Solution 4: Plain and basic +1 counter and save the value in local file. This ensures the uniqueness of sequence number and sequence number will resume when restart the program.
Issue: Too much file write will slow down the program.

Solution 5: Plain and basic +1 counter with cache, similar to Oracle sequence cache. When cache is used up, renew it and save the new cache value in local file.
Issue: When the program or server crashes, local file is not updated and we don’t know where the last sequence number.

Solution 6: Enhanced version 5. When program is restarted, sequence counter will start from previous cache.
Issue: This behavior is the same as Oracle sequence generator. Un-used sequence number is lost when program is restarted.

Solution 7: Enhanced version 6. With the help of Java ShutdownHock, we’ll save current and new cache value in the file. Local file will be updated when
1)Program is properly shutdown, ShutdownHock will store [Current count, current count].
2)When new cache is created, store [Current count, new cache]

So, when program is restarted, it will read the file and compare,
1)If Current count == current count, resume sequence number = Current count.
2)If Current count < new cache, it means program crashed previously. Sequence number will start from new cache + 1.

So far Solution 7 is quite good. It is clean and light-weight.

Interesting observation is,
1) Many people would think until Solution 4, 5, 6 and got stuck.
2) When 1 person is working alone, it is not easy to get out of blind spot.
3) The best solution indeed is not known or given. The best solution is purified from questioning and brain-storming with a team of good colleagues.

Wednesday, August 24, 2016

Renew Tenancy Renewal Offer

From MY HDB PAGE, go
MY BUSINESS -> Industrial Properties -> Tenant

After completion, print out the following:
1. Acceptance Letter
2. Deed of Guarantee (print 2 pages to 1 front of back)
3. Company Resolution , must be on paper with company letter head.

The rest can be ignored.

Mail to:
Housing and Development Board
Industrial Properties Group
480 Lorong 6 Toa Payoh
HDB Hub East Wing 21st Storey,
Singapore 310480
Attn: xxx

Friday, February 05, 2016

Java 8 collections content order

It is observed that in Java 8, the content in Collections has different order than previous Java.

To compare the equality of content in two Collections, the safer strategy becomes:

1. Convert name=value pair to Collections.

2. assertTrue(org.apache.commons.collections.CollectionUtils.isEqualCollection(Collection a, Collection b));

Tuesday, November 24, 2015

compile single executable jar file with maven


There are 2 ways of doing it.

(1) To include other jars:


The jar file itself contains all the classpath dependencies:
java -cp Target.jar or
java -jar Target.jar

(2) To include extracted classes:


The jar file itself is executable:
java -jar Target.jar

Thursday, November 19, 2015

Java output raw http get post

The following shows how Java write raw http GET and POST request via socket.

// Break down destinationURL.
// Reference: aURL = new;
String sProtocol = aURL.getProtocol();
String sHost = aURL.getHost();
int iPort = aURL.getPort();
if (iPort == -1) {
  if (sProtocol.equals("https")) {
    iPort = 443;
  } else {
    iPort = 80;
String sPath = aURL.getPath();
String sQuery = aURL.getQuery();
if (sQuery == null) { sQuery = parameters; } else { sQuery = sQuery + "&" + parameters; }

// Create socket. clientSocket;
if (sProtocol.equalsIgnoreCase("https")) {
   clientSocket = SSLSocketFactory.getDefault().createSocket(sHost,iPort);
} else {
   clientSocket = new,iPort);
// Connect to server. output = clientSocket.getOutputStream();
//output.write(("GET " + sPath + "?" + sQuery + " HTTP/1.1\r\n").getBytes("UTF-8"));
//output.write(("Host: " + sHost + "\r\n").getBytes("UTF-8"));
//output.write("Connection: close\r\n".getBytes("UTF-8")); // So the server will close socket immediately.
//output.write("\r\n".getBytes("UTF-8")); // HTTP1.1 requirement: last line must be empty line.
output.write(("POST " + sPath + " HTTP/1.1\r\n").getBytes("UTF-8"));
output.write(("Host: " + sHost + "\r\n").getBytes("UTF-8"));
output.write(("Content-Type: application/x-www-form-urlencoded\r\n").getBytes("UTF-8"));
output.write(("Content-Length: " + sQuery.length() + "\r\n").getBytes("UTF-8"));
output.write(("Connection: close\r\n").getBytes("UTF-8")); // So the server will close socket immediately.
output.write(("\r\n" + sQuery).getBytes("UTF-8"));
output.flush(); in = clientSocket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String inputLine = "";
while ((inputLine = reader.readLine()) != null) {
System.out.println("HTTP Response = [" + response + "]");

Dynamic way to compose http parameters:

String userpass = org.apache.commons.codec.binary.Base64.encodeBase64("username:password".getBytes("UTF-8"))

import java.util.*;

class Test {
    public static void main(String[] args) throws Exception {
        URL url = new URL("");
        Map<String,Object> params = new LinkedHashMap<>();
        params.put("name", "Freddie the Fish");
        params.put("email", "");
        params.put("reply_to_thread", 10394);
        params.put("message", "Shark attacks in Botany Bay have gotten out of control. We need more defensive dolphins to protect the schools here, but Mayor Porpoise is too busy stuffing his snout with lobsters. He's so shellfish.");

        StringBuilder postData = new StringBuilder();
        for (Map.Entry<String,Object> param : params.entrySet()) {
            if (postData.length() != 0) postData.append('&');
            postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
            postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
        byte[] postDataBytes = postData.toString().getBytes("UTF-8");

        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
        conn.setRequestProperty("Authorization", "Basic ${userpass}")        
conn.setDoOutput(true); conn.getOutputStream().write(postDataBytes); Reader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8")); for (int c; (c = >= 0;) System.out.print((char)c); } }


Wednesday, October 14, 2015

Chrome DevTools

Usage of Chrome Dev Tools.

Thursday, August 28, 2014

strategies to write log file log4j on other server computer

1. Using log4j's SimpleSocketServer

In your server you can just start server with the following parameters:
java -cp log4j.jar 4712

Here is sample for the server:
log4j.rootLogger=debug, stdout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n

Here is sample for the client:

2. Using Linux / Ubuntu rsyslog

Step 1 vi /etc/rsyslog.conf

= = = = = = = Enable UDP (Tested not working) = = = = = = =
# specific ruleset for remote messages
$Ruleset udpremote
*.* /var/log/updremote.log
# switch back to default ruleset
$Ruleset RSYSLOG_DefaultRuleset

# provides UDP syslog reception
$ModLoad imudp
$InputUDPServerBindRuleset udpremote
$UDPServerRun 514

= = = = = = = Enable TCP = = = = = = =
# specific ruleset for remote messages
$Ruleset tcpremote
*.* /var/log/tcpremote.log
# switch back to default ruleset
$Ruleset RSYSLOG_DefaultRuleset

# provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerBindRuleset tcpremote
$InputTCPServerRun 10514

Step 2 service rsyslog restart

Here is sample for the client:
log4j.appender.SYSLOG.layout.ConversionPattern=[%X{ref}] %-5p %C{1}:%L %m%n