Sorry if this shows up twice. It didn't appear in the archive list and it
wasn't forwarded to me.

A few people have asked in other threads about implementing a Unique ID
Generator. A few people were debating whether it could be implemented as an
EJB, and if so, would it be a session bean or entity bean. There are
probably many ways to approach the problem, so I would be interested in
other opinions as well.

Many clients will need to share a UID object. These clients would frequently
be EJB's themselves, since UID generation is a key part to creating primary
keys for most entity beans. The UID entity bean will return a sufficiently
unique integer value to any client that calls it. The business process that
I chose to implement this "unique" number is as follows:

    1. Split a timestamp (long) into two int's.
    2. Increment a sequence counter (int).
    3. Use the java.util.zip.CRC32 class to generate a CRC value for
       these 3 integer values.
    4. Return this value.

In order to accomplish this, I implemented an entity bean that uses
bean-managed persistence (BMP). The bean actually performs no persistence,
so I provide empty implementations of the ejbXXX methods. There is no need
for persistence because of the business logic in the getUID() method. As
long as the sequence counter is incremented on each call, the CRC value
should be unique. If the EJB Server is restarted, the counter will reset to
0 (and increment again), but the timestamp will be different. This should
keep the resulting values unique and sufficently fast for most demanding
applications.

I'm not up on whether CRC32 is effective at generating truly unique numbers
given 3 unique input values. Maybe someone else can either verify that it is
sufficient or provide an alternative method. I used to know the RFC for
generating a UUID, but I can't seem to find it now. It used information that
Java could have difficulty obtaining, such as NIC/MAC address.

Following is the source code for the bean. Please feel free to use it
anywhere you wish for any purpose. Also, your feedback is appreciated. I've
attached the compiled source that is ready to be deployed with WebLogic
Server.

jim

Remote Interface
=================
package com.vxs.ejb.uid;

import javax.ejb.*;
import java.rmi.*;

public interface UID extends EJBObject {

    /**
     *  Returns a unique identifier value as an integer.
     */
    public long getUID() throws RemoteException;
}

Home Interface
===============
package com.vxs.ejb.uid;

import javax.ejb.*;
import java.rmi.*;

public interface UIDHome extends EJBHome {

    /**
     *  This will be the preferred method of locating/creating the UID bean.
     *  This isn't usual for the create method to have no parameters, but we
     *  want to be sure that all clients are using the same instance of the
     *  bean.
     */
    public UID create() throws java.rmi.RemoteException,
javax.ejb.CreateException;

    /**
     *  The findByPrimaryKey method is required by the EJB spec. If the
client
     *  uses this method, the primary key object that they pass in will be
     *  irrelevant. This is done to ensure the same instance of the bean is
     *  always used.
     */
    public UID findByPrimaryKey(UIDPK primaryKey) throws RemoteException,
FinderException;
}

Enterprise JavaBean
====================
package com.vxs.ejb.uid;

import java.rmi.*;
import javax.ejb.*;
import java.util.zip.CRC32;

public class UIDBean implements EntityBean {
    private EntityContext entityContext;
    private CRC32 crc = new CRC32();
    private int sequenceID;
    private int a,b;

    /**
     *  The create method is guaranteed to be executed at least once. It is
here
     *  that the timestamp value is read. The timestamp is split into two
     *  integer values, as well. Note the return of a bogus primary key
object.
     */
    public UIDPK ejbCreate() throws RemoteException, CreateException {
        long now = System.currentTimeMillis();
        a = (int)(now >> 32);
        b = (int) now;
        return new UIDPK();
    }

    public void ejbPostCreate() throws  CreateException {
    }

    /**
     *  The CRC32 object is reset and fed the two timestamp integers. Next,
the
     *  sequence number is crunched, and sunsequently incremented. The
     *  calculated CRC value is then returned.
     */
    public long getUID() throws RemoteException {
        crc.reset();
        crc.update(a);
        crc.update(b);
        crc.update(sequenceID++);
        return crc.getValue();
    }

    public UIDPK ejbFindByPrimaryKey(UIDPK uidPk){
        return new UIDPK();
    }

    public void ejbActivate() throws RemoteException {
    }

    public void ejbLoad() throws RemoteException {
    }

    public void ejbPassivate() throws RemoteException {
    }

    public void ejbRemove() throws RemoteException, RemoveException {
    }

    public void ejbStore() throws RemoteException {
    }

    public void setEntityContext(EntityContext context) throws
RemoteException {
        entityContext = context;
    }

    public void unsetEntityContext() throws RemoteException {
        entityContext = null;
    }
}

EJB Primary Key
================
package com.vxs.ejb.uid;

public class UIDPK implements java.io.Serializable {

    public long id;

    /**
     *  This EJB primary key is a little different than most. The UID EJB
does
     *  not represent a variety of different instances with different data.
     *  In this case, there will only be one unique instance of our bean on
the
     *  system. This will ensure that every client will go through our bean
for
     *  service.
     *
     *  To this end, the primary key's id value will always return 0.
     */
    public UIDPK() {
        id = 0;
    }

    public boolean equals(Object parm1) {
        return super.equals( parm1);
    }

    public int hashCode() {
        return super.hashCode();
    }

    public String toString() {
        return "UIDPK: " + id;
    }
}

Test Client
============
package com.vxs.ejb.uid;

import javax.naming.*;
import java.io.*;
import java.rmi.*;
import java.util.*;

public class UIDClient {

    private static PrintStream o  = System.out;

    public static void main(String[] args) {
        try{
            Context jndiContext = getWebLogicContext();
            o.println("Context retrieved: " + jndiContext);
            UIDHome uidHome = (UIDHome)jndiContext.lookup("uid");

            UID     uid = uidHome.create();
            for (int i=0; i< 100; i++) {
                long x = uid.getUID();
                System.out.println(x);
            }
        } catch (Throwable t){t.printStackTrace();}

    }

    public static Context getWebLogicContext() throws
javax.naming.NamingException {
        Properties p = new Properties();

p.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory
");
        p.put(Context.PROVIDER_URL,"t3://localhost:7001");

        o.println("Obtaining context: " + p);

        return new InitialContext(p);
    }

}

===========================================================================
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff EJB-INTEREST".  For general help, send email to
[EMAIL PROTECTED] and include in the body of the message "help".

Reply via email to