Sunday, December 17, 2006

Smart Key Generator ejb3


Java Persistence provides facility for auto-generation of primary keys. But limited to integer datatype. Further there is no convenient way to access these generated values. Its often needed that the primary key is a combination of identifiable data. Such keys are also known as Smart Keys.
Smart Keys also need automatic serial number generation.
Following solution uses HiLo sequence generation algorithm.

The solution contains one Stateless Session Bean and a Singleton. Additionally it consists an Entity (JPA)


package jkook.vetan.utils;
/*
* HrSequenceFacade.java
*/
@Stateless
public class HrSequenceFacade implements HrSequenceFacadeLocal, HrSequenceFacadeRemote {


@PersistenceContext
private EntityManager em;

private UIDDispenser uiddispenser;
private static final Logger log = Logger.getLogger(HrSequence.class.getName());

/** Creates a new instance of HrSequenceFacade */
public HrSequenceFacade() {

}

public void create(HrSequence hrSequence) {
em.persist(hrSequence);
}


public void edit(HrSequence hrSequence) {
em.merge(hrSequence);
em.flush();
log.info("HrSequence Updated");

}

public void destroy(HrSequence hrSequence) {
em.merge(hrSequence);
em.remove(hrSequence);
}

public HrSequence find(Object pk) {
return (HrSequence) em.find(HrSequence.class, pk);
}

public List findAll() {
return em.createQuery("select object(o) from HrSequence as o").getResultList();
}

/*
if dispenser is null
create new dispenser
getnextHi from dispenser

*/

@TransactionAttribute(TransactionAttributeType.REQUIRED)
public Integer getNextID(String entityname) {
log.info(" getNextId called");
uiddispenser = UIDDispenser.getDispenser(em);
return uiddispenser.getNextID(entityname,em);
}

public Integer getCount() {
Query q = em.createQuery("select count(o) from HrSequence as o ");
Long count = (Long)q.getSingleResult();
if(count != null){
return count.intValue();
}
return null;
}

public Integer getCurrentID(String entityname) {
uiddispenser = UIDDispenser.getDispenser(em);
return uiddispenser.getCurrentID(entityname);
}
}



/*
* UIDDispenser.java
*
*/

package jkook.vetan.utils;

public class UIDDispenser {


private static UIDDispenser uiddispenser;
private Map allentries;
private static final byte maxLo = 25;
static Logger log = Logger.getLogger(UIDDispenser.class.getName());
/** Creates a new instance of UIDDispenser */
private UIDDispenser() {

}

private UIDDispenser(EntityManager em){
// populate all entries
Iterator i =
em.createQuery("select object(o) from HrSequence as o")
.getResultList()
.iterator();
// for large database initiate the hashmap with count of HrSequence
allentries = new HashMap();
while(i.hasNext()){
HrSequence hs = i.next();
hs.setNextHi(hs.getNextHi()+maxLo);
allentries.put(hs.getEntityname(),hs);
System.err.println(" enityties +++ "+hs.getEntityname());
}

}

public static synchronized UIDDispenser getDispenser( EntityManager em) {
if (uiddispenser == null)
return new UIDDispenser(em);
return uiddispenser;

}

/*
* get nextLo
if lo > max_lo getnext HI
set lo=0
return HI+Lo
*
*
*/
public synchronized Integer getNextID(String entityname, EntityManager em){

HrSequence hs = allentries.get(entityname);
if(hs.getLo() >=maxLo){
log.fine(" LO Val is > maxLo " +hs.getLo() + " maxLo is " + maxLo );
hs.setNextHi(hs.getNextHi()+maxLo);
em.merge(hs);
byte b=0;
hs.setLo(b);
log.fine("Updated HI_VAL");
}
return hs.getNextHi()+ hs.getNextLo();
}

public Integer getCurrentID(String entityname){
HrSequence hs = allentries.get(entityname);
return hs.getNextHi()+ hs.getLo();
}
}

Usage :
@EJB HrSequenceFacade hrSequenceFacade
{
....
....
// start of smart key generation
// smartkey part1
// smartkey part2
Integer nextSerial = hrSequenceFacade.getNextID("NameityOfTheEnt")
// primaryKey = smartkeypart1 + part2 + nextSerial



Ref : Using Primary Keys with Java Persistence

No comments: