When attempting to remove a bean that has cascading deletion defined on its relationship
to another bean, I sometimes receive an NPE when the removal is attempted. The relevant
portion of the stack trace is as follows:
| 14:03:34,448 INFO [STDOUT]
com.gg.security.permissions.exception.PermissionsException: Could not delete old
permissions for [FolderContainedEntityEJB: path='testperm/test1',
parentPath='testperm', id='7fbc44610a0001ee01cb95b31eb23fd7']: Could not
delete entity: null
| 14:03:34,449 INFO [STDOUT] at
com.gg.model.security.permissions.modify.PermissionsModifierImpl.deletePermissions(PermissionsModifierImpl.java:237)
| 14:03:34,449 INFO [STDOUT] at
com.gg.model.security.permissions.modify.PermissionsModifierImpl.ensurePermissions(PermissionsModifierImpl.java:216)
| 14:03:34,449 INFO [STDOUT] at
com.gg.model.security.permissions.modify.PermissionsModifierImpl.modify(PermissionsModifierImpl.java:70)
| ...
| 14:03:34,460 INFO [STDOUT] Caused by: java.lang.NullPointerException
| 14:03:34,460 INFO [STDOUT] at
org.jboss.ejb.plugins.cmp.jdbc.JDBCStoreManager$CascadeDeleteRegistry.unschedule(JDBCStoreManager.java:752)
| 14:03:34,460 INFO [STDOUT] at
org.jboss.ejb.plugins.cmp.jdbc.JDBCStoreManager.unscheduledCascadeDelete(JDBCStoreManager.java:259)
| 14:03:34,460 INFO [STDOUT] at
org.jboss.ejb.plugins.cmp.jdbc.CascadeDeleteStrategy$BatchCascadeDeleteStrategy.cascadeDelete(CascadeDeleteStrategy.java:168)
| 14:03:34,461 INFO [STDOUT] at
org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCCMRFieldBridge.cascadeDelete(JDBCCMRFieldBridge.java:406)
| 14:03:34,461 INFO [STDOUT] at
org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCEntityBridge.cascadeDelete(JDBCEntityBridge.java:322)
| 14:03:34,461 INFO [STDOUT] at
org.jboss.ejb.plugins.cmp.jdbc.JDBCRemoveEntityCommand.execute(JDBCRemoveEntityCommand.java:117)
| 14:03:34,461 INFO [STDOUT] at
org.jboss.ejb.plugins.cmp.jdbc.JDBCStoreManager.removeEntity(JDBCStoreManager.java:682)
| 14:03:34,461 INFO [STDOUT] at
org.jboss.ejb.plugins.CMPPersistenceManager.removeEntity(CMPPersistenceManager.java:466)
| 14:03:34,461 INFO [STDOUT] at
org.jboss.resource.connectionmanager.CachedConnectionInterceptor.removeEntity(CachedConnectionInterceptor.java:457)
| 14:03:34,461 INFO [STDOUT] at
org.jboss.ejb.EntityContainer.remove(EntityContainer.java:500)
| 14:03:34,461 INFO [STDOUT] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
Method)
| 14:03:34,461 INFO [STDOUT] at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
| 14:03:34,461 INFO [STDOUT] at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
| 14:03:34,461 INFO [STDOUT] at java.lang.reflect.Method.invoke(Method.java:585)
| 14:03:34,461 INFO [STDOUT] at
org.jboss.ejb.EntityContainer$ContainerInterceptor.invoke(EntityContainer.java:1107)
| 14:03:34,461 INFO [STDOUT] at
org.jboss.ejb.plugins.cmp.jdbc.JDBCRelationInterceptor.invoke(JDBCRelationInterceptor.java:72)
| 14:03:34,461 INFO [STDOUT] at
org.jboss.ejb.plugins.EntitySynchronizationInterceptor.invoke(EntitySynchronizationInterceptor.java:345)
| 14:03:34,461 INFO [STDOUT] at
org.jboss.resource.connectionmanager.CachedConnectionInterceptor.invoke(CachedConnectionInterceptor.java:186)
| 14:03:34,462 INFO [STDOUT] at
org.jboss.ejb.plugins.EntityReentranceInterceptor.invoke(EntityReentranceInterceptor.java:116)
| 14:03:34,462 INFO [STDOUT] at
org.jboss.ejb.plugins.EntityInstanceInterceptor.invoke(EntityInstanceInterceptor.java:211)
| 14:03:34,462 INFO [STDOUT] at
org.jboss.ejb.plugins.EntityLockInterceptor.invoke(EntityLockInterceptor.java:89)
| 14:03:34,462 INFO [STDOUT] at
org.jboss.ejb.plugins.EntityCreationInterceptor.invoke(EntityCreationInterceptor.java:54)
| 14:03:34,462 INFO [STDOUT] at
org.jboss.ejb.plugins.AbstractTxInterceptor.invokeNext(AbstractTxInterceptor.java:84)
| 14:03:34,462 INFO [STDOUT] at
org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:343)
| 14:03:34,462 INFO [STDOUT] at
org.jboss.ejb.plugins.TxInterceptorCMT.invoke(TxInterceptorCMT.java:150)
| 14:03:34,462 INFO [STDOUT] at
org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:111)
| 14:03:34,462 INFO [STDOUT] at
org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor.invoke(ProxyFactoryFinderInterceptor.java:122)
| 14:03:34,462 INFO [STDOUT] at
org.jboss.ejb.EntityContainer.internalInvoke(EntityContainer.java:484)
| 14:03:34,462 INFO [STDOUT] at org.jboss.ejb.Container.invoke(Container.java:709)
| 14:03:34,472 INFO [STDOUT] at
org.jboss.ejb.plugins.local.BaseLocalProxyFactory.invoke(BaseLocalProxyFactory.java:419)
| 14:03:34,472 INFO [STDOUT] at
org.jboss.ejb.plugins.local.EntityProxy.invoke(EntityProxy.java:44)
| 14:03:34,472 INFO [STDOUT] at $Proxy271.remove(Unknown Source)
| 14:03:34,472 INFO [STDOUT] at
com.gg.adapter.BaseEntityAdapter.remove(BaseEntityAdapter.java:90)
| 14:03:34,473 INFO [STDOUT] at
com.gg.model.delete.BaseEntityDeleter.delete(BaseEntityDeleter.java:24)
| 14:03:34,473 INFO [STDOUT] at
com.gg.manager.remove.EntityRemoverImpl.removeEntity(EntityRemoverImpl.java:35)
| 14:03:34,473 INFO [STDOUT] ... 66 more
|
The basic scenario is that a folder in the app has some permissions, which in turn are
defined by a number of "access control list entries" (aka ACLEntries). Thus, a
one-to-many CMR relationship between the Permissions and ACLEntry beans, which is defined
like so:
PermissionsBean.java
| /**
| * @ejb.bean
| * name="Permissions"
| * type="CMP"
| * view-type="local"
| * local-jndi-name="ejb/Permissions"
| * reentrant="false"
| * primkey-field="id"
| * schema="Permissions"
| * transaction-type="Container"
| * cmp-version="2.x"
| *
| * @ejb.interface
| * local-class="com.gg.model.security.permissions.interfaces.Permissions"
| * local-extends="com.hannonhill.object.interfaces.BaseEntity"
| * @ejb.home
| *
local-class="com.gg.model.security.permissions.interfaces.PermissionsHome"
| * local-extends="javax.ejb.EJBLocalHome"
| *
| * @ejb.pk
| * class="java.lang.String" extends="java.lang.Object"
| *
| * @jboss.persistence
| * create-table="true"
| *
| * @ejb.persistence
| * table-name="permissions"
| *
| * @ejb.util
| * generate="physical"
| *
| * @jboss.container-configuration
| * name="CMP 2.x and Cache"
| *
| * @ejb.transaction
| * type="Supports"
| *
| */
| public abstract class PermissionsBean extends BaseEntityBean implements
PermissionsLevels
| {
| <!-- some unrelated ejb code -->
|
| /**
| * Returns a collection of ACLEntries this Permissions object contains.
| *
| * @ejb.relation
| * name="aclentry-has-permissions"
| * role-name="permission-aclentrys"
| * target-ejb="ACLEntry"
| * @ejb.interface-method
| * view-type="local"
| *
| * @jboss.method-attributes
| * read-only="true"
| */
| public abstract java.util.Collection getACLEntries();
|
| /**
| * sets the Collection of Destination objects for this Target.
| *
| * @ejb.interface-method
| * view-type="local"
| * @ejb.transaction
| * type="Required"
| */
| public abstract void setACLEntries(java.util.Collection aclEntries);
|
| /**
| * Deletes this entity.
| */
| public void ejbRemove() throws RemoveException
| {
| super.ejbRemove();
| }
|
| <!-- more unrelated ejb stuff -->
| }
|
ACLEntryBean.java
| /**
| * @ejb.bean
| * name="ACLEntry"
| * type="CMP"
| * view-type="local"
| * local-jndi-name="ejb/ACLEntry"
| * reentrant="false"
| * primkey-field="id"
| * schema="ACLEntry"
| * transaction-type="Container"
| * cmp-version="2.x"
| *
| * @ejb.interface
| * local-class="com.gg.model.security.permissions.interfaces.ACLEntry"
| * local-extends="com.hannonhill.object.interfaces.BaseEntity"
| * @ejb.home
| * local-class="com.gg.security.permissions.interfaces.ACLEntryHome"
| * local-extends="javax.ejb.EJBLocalHome"
| *
| * @ejb.pk
| * class="java.lang.String" extends="java.lang.Object"
| *
| * @jboss.persistence
| * create-table="true"
| *
| * @ejb.persistence
| * table-name="aclentry"
| *
| * @ejb.util
| * generate="physical"
| *
| * @jboss.container-configuration
| * name="CMP 2.x and Cache"
| *
| * @ejb.transaction
| * type="Supports"
| *
| * @ejb.finder
| * signature="com.gg.security.permissions.interfaces.ACLEntry
findByPrimaryKey(java.lang.String pk)"
| * query="SELECT OBJECT(x) FROM ACLEntry AS x WHERE x.id = ?1"
| */
| public abstract class ACLEntryBean extends BaseEntityBean
| {
| <!-- some unrelated ejb stuff -->
|
| /**
| * @ejb.relation
| * name="aclentry-has-permissions"
| * role-name="aclentry-permissions"
| * target-ejb="Permissions"
| * cascade-delete="yes"
| * @jboss.relation
| * related-pk-field="id"
| * fk-column="permissionsId"
| * batch-cascade-delete="true"
| *
| * @ejb.interface-method
| * view-type="local"
| *
| * @jboss.method-attributes
| * read-only="true"
| */
| public abstract com.gg.security.permissions.intefaces.Permissions
getPermissions();
|
| /**
| * @ejb.interface-method
| * view-type="local"
| * @ejb.transaction
| * type="Required"
| */
| public abstract void setPermissions(Permissions permissions);
|
| /**
| * Vanilla ejb remove.
| */
| public void ejbRemove() throws RemoveException
| {
| super.ejbRemove();
| }
|
| <!-- more ejb junk here -->
| }
|
The deletion of these beans is accomplished through calling
PermissionsModifierImpl.deletePermissions(...), which you see in the stack trace above.
PermissionsModifierImpl.java
| /**
| * Deletes the permissions object associated with this entity.
| * @param entity
| */
| private void deletePermissions(PermissionsCapable entity) throws
PermissionsException
| {
| EntityRemover remover = getEntityManagerFactory().getManager().getRemover();
| MutablePermissions permissions = entity.getPermissions();
| if (permissions != null)
| {
| try
| {
| remover.removeEntity(entity.getPermissions());
| entity.setPermissions(null);
| }
| catch (Exception e)
| {
| throw new PermissionsException("Could not delete old permissions
for " + entity + ": " + e.getMessage(), e);
| }
| }
| }
|
Curiously, a failed deletion leaves the child folder bean in a state where its permissions
are null, and attempting the modification again will result in success. If the permissions
are set on the child folder bean after the failed modification, however, the subsequent
modification will also fail.
We are using similar cascading deletion in other places in our application with no
problems. Any ideas as to why this might be happening?
View the original post :
http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4031747#...
Reply to the post :
http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&a...