2
\$\begingroup\$

For my web application I have to generate a sequence of following format:

<year><sometext><month><sequence> 

For example:

2014TOYS11000001 -> for first sequence of month of November this year. If month has changed, we have to reset the sequence to 1.

The application is Spring-based, and I have used NoSQL (Mongodb) to persist the sequence. NoSQL because we already have Mongodb usage in the application and this sequence that is generated is not used to refer anything in the backend database(Oracle).

Here is my implementation: an API of String nextVal() backed by a HashMap maintained in Mongodb.

import my.dao.MongoDao; import org.springframework.beans.factory.annotation.Autowired; import java.io.Serializable; import java.util.Calendar; import java.util.HashMap; import java.util.Map; public final class MySequence { private final String SEQUENCE_TEXT = "TOYS"; private final String SEQUENCE_FORMAT = "%d%s%02d%010d"; private static final String KEY_ID = "id"; private static final String KEY_MONTH = "month"; private static final String KEY_SEQNB = "seq_nb"; private static Map<String, String> seqData; @Autowired private MongoDao mongoDao; public MySequence() { } public String nextVal() { synchronized(seqData){ seqData = mongoDao.findById(HashMap.class, SEQUENCE_TEXT); if (seqData == null) { //create new hash map with starting values and persist. seqData = new HashMap<String, String>(3); initSequenceDataMap(seqData); //save new map with "id" map field as the id to use in DB mongoDao.addObject(seqData, KEY_ID); } else { int currentMonth = Calendar.getInstance().get(Calendar.MONTH) + 1; int monthInDb = Integer.parseInt(seqData.get(KEY_MONTH)); if (currentMonth != monthInDb) { //reset sequence for the month initSequenceForMonth(seqData, currentMonth); } else { incrementSequenceNumber(seqData); } mongoDao.update(seqData); } } return mapToString(seqData); } private void incrementSequenceNumber(Map<String, String> seqData) { int seqNum = Integer.parseInt(seqData.get(KEY_SEQNB)); seqNum++; seqData.put(KEY_SEQNB, seqNum + ""); } private void initSequenceDataMap(Map<String, String> seqData) { seqData.put(KEY_ID, SEQUENCE_TEXT); int month = Calendar.getInstance().get(Calendar.MONTH) + 1; initSequenceForMonth(seqData, month); } private void initSequenceForMonth(Map<String, String> dataMap, int month) { dataMap.put(KEY_MONTH, month + ""); dataMap.put(KEY_SEQNB, "1"); } private String mapToString(Map<String, String> seqData) { return String.format(SEQUENCE_FORMAT, Calendar.getInstance().get(Calendar.YEAR),SEQUENCE_TEXT, Integer.valueOf(seqData.get(KEY_MONTH)), Integer.valueOf(seqData.get(KEY_SEQNB))); } public GenericMongoDao getGenericMongoDao() { return mongoDao; } public void setGenericMongoDao(MongoDao mongoDao) { this.mongoDao = mongoDao; } } 

Concerns:

  • Is this thread-safe even when two separate beans can be created?
  • Is there a way to achieve less ceremonious call such as `MySequence.nextVal() using spring?
  • Any other improvements?
\$\endgroup\$
1
  • \$\begingroup\$If you are afraid of multiple instances why not inject the class or use a singleton?\$\endgroup\$CommentedDec 12, 2014 at 21:44

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.