2 Replies Latest reply on Mar 11, 2005 3:06 AM by ebu

    Referential Integrity

    ebu

      Hi.

      Unfortunately i did not receive any answers to the question about referential integrity i had posted more than week ago (http://www.jboss.org/index.html?module=bb&op=viewtopic&t=60776). The matter is in making it impossible to delete an entity bean instance while it is referenced from some other entity bean instance. Actually, this is common behavior of any relational database, but this contradicts with ejb spec which states that

      ...After the Bean Provider?s ejbRemove method returns (and prior to returning to the client), the container must remove the entity object from all relationships in which it participates, and then remove its persistent representation.


      The only solution i can see is to opt for capabilities of underling ER persistence layer and to to implement special interceptor to be inserted in the entity bean's interceptors chain. As far as i understood JBoss CMP APIs i sketched it as following:

      /*
       * Created on 04.03.2005 13:45:27
       *
       */
      package test.ejb;
      
      import java.rmi.RemoteException;
      
      import org.jboss.ejb.EntityContainer;
      import org.jboss.ejb.EntityEnterpriseContext;
      import org.jboss.ejb.EntityPersistenceManager;
      import org.jboss.ejb.plugins.AbstractInterceptor;
      import org.jboss.ejb.plugins.CMPPersistenceManager;
      import org.jboss.ejb.plugins.cmp.jdbc.JDBCStoreManager;
      import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCCMRFieldBridge;
      import org.jboss.invocation.Invocation;
      
      /**
       * @author bushuyev
       *
       */
      public class DeletionInterceptor extends AbstractInterceptor {
      
       private EntityPersistenceManager pm;
      
       public void start() throws Exception {
       if (this.container instanceof EntityContainer) {
       EntityContainer ec = (EntityContainer)container;
       this.pm = ec.getPersistenceManager();
      
       }
       }
      
       public Object invoke(Invocation invocation) throws Exception {
      
       if (invocation.getMethod() != null && invocation.getMethod().getName().equals("remove")) { //$NON-NLS-1$
       org.jboss.ejb.EntityEnterpriseContext ctx = (EntityEnterpriseContext)invocation.getEnterpriseContext();
      
      
       if (
       ((JDBCCMRFieldBridge)((JDBCStoreManager)((CMPPersistenceManager)this.pm).
       getPersistenceStore()).getEntityBridge().
       getCMRFields()[0]).getRelatedCMRField().hasForeignKey()
      
       &&
      
       ((JDBCStoreManager)((CMPPersistenceManager)this.pm).
       getPersistenceStore()).getEntityBridge().
       getCMRFields()[0].getInstanceValue(ctx) != null
      
       ) {
       throw new RemoteException("Can't delete "+ctx.getEJBContext().getEJBLocalHome()+" with id="+invocation.getId()+" cause it is referenced from "+((JDBCCMRFieldBridge)((JDBCStoreManager)((CMPPersistenceManager)this.pm).
       getPersistenceStore()).getEntityBridge().getCMRFields()[0]).getRelatedCMRField().getEntity().getLocalInterface()); //$NON-NLS-1$
       }
      
       }
      
       return super.invoke(invocation);
       }
      
      
       public Object invokeHome(Invocation invocation) throws Exception {
      
       return super.invokeHome(invocation);
       }
      }
      
      



      Could somebody with thorough knowledge of JBoss CMP internals glance at this code and say if it is acceptable? Aren't there some issues with caching, lazy loading or something else which might prevent it from working correctly?

      wbr, eugen.

        • 1. Re: Referential Integrity
          aloubyansky

          It looks ok (the interceptor must be executed after the lock and instance interceptor) but wouldn't it be simpler to include the logic into the bean's ejbRemove method?

          • 2. Re: Referential Integrity
            ebu

            Yes, implementing checks in the ejbRemoves would be simpler but also error-prone. I think that "foreign key" approach to the data integrity is much more valuable when dealing with enterprise data, when implicit data modification might cause severe consequences.

            Besides this, as far as i can see it is impossible to check in the ejbRemove references to the objects being deleted unless we make all relationships bidirectional. Consider unidirectional many-to-one relationship from B to A, i.e. B has a getter for A, but A has no getters for collection of related Bs. In this case when A is being deleted there is no way to check for related Bs in ejbRemove. Or i'm missing something?

            thanx.