1 22 package org.jboss.ejb.plugins.cmp.jdbc; 23 24 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCCMRFieldBridge; 25 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCEntityBridge; 26 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCRelationshipRoleMetaData; 27 import org.jboss.ejb.EntityEnterpriseContext; 28 import org.jboss.ejb.EntityContainer; 29 import org.jboss.logging.Logger; 30 import org.jboss.deployment.DeploymentException; 31 import org.jboss.security.SecurityAssociation; 32 33 import javax.ejb.RemoveException ; 34 import javax.ejb.EJBObject ; 35 import javax.ejb.EJBLocalObject ; 36 import java.util.List ; 37 import java.util.ArrayList ; 38 import java.util.Map ; 39 import java.util.HashMap ; 40 import java.sql.Connection ; 41 import java.sql.PreparedStatement ; 42 import java.security.PrivilegedAction ; 43 import java.security.Principal ; 44 import java.security.AccessController ; 45 import java.rmi.RemoteException ; 46 47 52 public abstract class CascadeDeleteStrategy 53 { 54 57 public static final class NoneCascadeDeleteStrategy 58 extends CascadeDeleteStrategy 59 { 60 public NoneCascadeDeleteStrategy(JDBCCMRFieldBridge cmrField) throws DeploymentException 61 { 62 super(cmrField); 63 } 64 65 public void removedIds(EntityEnterpriseContext ctx, Object [] oldRelationRefs, List ids) 66 { 67 cmrField.setInstanceValue(ctx, null); 68 } 69 70 public void cascadeDelete(EntityEnterpriseContext ctx, List oldValues) throws RemoveException , RemoteException 71 { 72 boolean trace = log.isTraceEnabled(); 73 for(int i = 0; i < oldValues.size(); ++i) 74 { 75 Object oldValue = oldValues.get(i); 76 if(relatedManager.unscheduledCascadeDelete(oldValue)) 77 { 78 if(trace) 79 { 80 log.trace("Removing " + oldValue); 81 } 82 83 invokeRemoveRelated(oldValue); 84 } 85 else if(trace) 86 { 87 log.trace(oldValue + " already removed"); 88 } 89 } 90 } 91 } 92 93 96 public static final class DefaultCascadeDeleteStrategy 97 extends CascadeDeleteStrategy 98 { 99 public DefaultCascadeDeleteStrategy(JDBCCMRFieldBridge cmrField) throws DeploymentException 100 { 101 super(cmrField); 102 } 103 104 public void removedIds(EntityEnterpriseContext ctx, Object [] oldRelationRef, List ids) 105 { 106 cmrField.scheduleChildrenForCascadeDelete(ctx); 107 scheduleCascadeDelete(oldRelationRef, new ArrayList (ids)); 108 cmrField.setInstanceValue(ctx, null); 109 } 110 111 public void cascadeDelete(EntityEnterpriseContext ctx, List oldValues) throws RemoveException , RemoteException 112 { 113 boolean trace = log.isTraceEnabled(); 114 for(int i = 0; i < oldValues.size(); ++i) 115 { 116 Object oldValue = oldValues.get(i); 117 if(relatedManager.unscheduledCascadeDelete(oldValue)) 118 { 119 if(trace) 120 { 121 log.trace("Removing " + oldValue); 122 } 123 invokeRemoveRelated(oldValue); 124 } 125 else if(trace) 126 { 127 log.trace(oldValue + " already removed"); 128 } 129 } 130 } 131 } 132 133 137 public static final class BatchCascadeDeleteStrategy 138 extends CascadeDeleteStrategy 139 { 140 private final String batchCascadeDeleteSql; 141 142 public BatchCascadeDeleteStrategy(JDBCCMRFieldBridge cmrField) 143 throws DeploymentException 144 { 145 super(cmrField); 146 147 if(cmrField.hasForeignKey()) 148 { 149 throw new DeploymentException( 150 "Batch cascade-delete was setup for the role with a foreign key: relationship " 151 + cmrField.getMetaData().getRelationMetaData().getRelationName() 152 + ", role " + cmrField.getMetaData().getRelationshipRoleName() 153 + ". Batch cascade-delete supported only for roles with no foreign keys." 154 ); 155 } 156 157 StringBuffer buf = new StringBuffer (100); 158 buf.append("DELETE FROM ") 159 .append(cmrField.getRelatedJDBCEntity().getQualifiedTableName()) 160 .append(" WHERE "); 161 SQLUtil.getWhereClause(cmrField.getRelatedCMRField().getForeignKeyFields(), buf); 162 batchCascadeDeleteSql = buf.toString(); 163 164 log.debug( 165 cmrField.getMetaData().getRelationMetaData().getRelationName() + " batch cascade delete SQL: " 166 + batchCascadeDeleteSql 167 ); 168 } 169 170 public void removedIds(EntityEnterpriseContext ctx, Object [] oldRelationRefs, List ids) 171 { 172 cmrField.scheduleChildrenForBatchCascadeDelete(ctx); 173 scheduleCascadeDelete(oldRelationRefs, new ArrayList (ids)); 174 } 175 176 public void cascadeDelete(EntityEnterpriseContext ctx, List oldValues) throws RemoveException , RemoteException 177 { 178 boolean didDelete = false; 179 boolean trace = log.isTraceEnabled(); 180 for(int i = 0; i < oldValues.size(); ++i) 181 { 182 Object oldValue = oldValues.get(i); 183 if(relatedManager.unscheduledCascadeDelete(oldValue)) 184 { 185 if(trace) 186 { 187 log.trace("Removing " + oldValue); 188 } 189 invokeRemoveRelated(oldValue); 190 didDelete = true; 191 } 192 else if(trace) 193 { 194 log.trace(oldValue + " already removed"); 195 } 196 } 197 198 if(didDelete) 199 { 200 executeDeleteSQL(batchCascadeDeleteSql, ctx.getId()); 201 } 202 } 203 } 204 205 public static CascadeDeleteStrategy getCascadeDeleteStrategy(JDBCCMRFieldBridge cmrField) 206 throws DeploymentException 207 { 208 CascadeDeleteStrategy result; 209 JDBCRelationshipRoleMetaData relatedRole = cmrField.getMetaData().getRelatedRole(); 210 if(relatedRole.isBatchCascadeDelete()) 211 { 212 result = new BatchCascadeDeleteStrategy(cmrField); 213 } 214 else if(relatedRole.isCascadeDelete()) 215 { 216 result = new DefaultCascadeDeleteStrategy(cmrField); 217 } 218 else 219 { 220 result = new NoneCascadeDeleteStrategy(cmrField); 221 } 222 return result; 223 } 224 225 protected final JDBCCMRFieldBridge cmrField; 226 protected final JDBCEntityBridge entity; 227 protected final JDBCStoreManager relatedManager; 228 protected final Logger log; 229 230 public CascadeDeleteStrategy(JDBCCMRFieldBridge cmrField) throws DeploymentException 231 { 232 this.cmrField = cmrField; 233 entity = (JDBCEntityBridge)cmrField.getEntity(); 234 relatedManager = cmrField.getRelatedManager(); 235 236 log = Logger.getLogger(getClass().getName() + "." + cmrField.getEntity().getEntityName()); 237 } 238 239 public abstract void removedIds(EntityEnterpriseContext ctx, Object [] oldRelationRefs, List ids); 240 241 public abstract void cascadeDelete(EntityEnterpriseContext ctx, List oldValues) throws RemoveException , 242 RemoteException ; 243 244 protected void scheduleCascadeDelete(Object [] oldRelationsRef, List values) 245 { 246 Map oldRelations = (Map )oldRelationsRef[0]; 247 if(oldRelations == null) 248 { 249 oldRelations = new HashMap (); 250 oldRelationsRef[0] = oldRelations; 251 } 252 oldRelations.put(cmrField, values); 253 relatedManager.scheduleCascadeDelete(values); 254 } 255 256 protected void executeDeleteSQL(String sql, Object key) throws RemoveException 257 { 258 Connection con = null; 259 PreparedStatement ps = null; 260 int rowsAffected = 0; 261 try 262 { 263 if(log.isDebugEnabled()) 264 log.debug("Executing SQL: " + sql); 265 266 con = entity.getDataSource().getConnection(); 268 ps = con.prepareStatement(sql); 269 270 entity.setPrimaryKeyParameters(ps, 1, key); 272 273 rowsAffected = ps.executeUpdate(); 275 } 276 catch(Exception e) 277 { 278 log.error("Could not remove " + key, e); 279 throw new RemoveException ("Could not remove " + key); 280 } 281 finally 282 { 283 JDBCUtil.safeClose(ps); 284 JDBCUtil.safeClose(con); 285 } 286 287 if(rowsAffected == 0) 289 { 290 log.error("Could not remove entity " + key); 291 throw new RemoveException ("Could not remove entity"); 292 } 293 294 if(log.isDebugEnabled()) 295 log.debug("Remove: Rows affected = " + rowsAffected); 296 } 297 298 public void invokeRemoveRelated(Object relatedId) throws RemoveException , RemoteException 299 { 300 EntityContainer container = relatedManager.getContainer(); 301 302 328 329 333 if(container.getLocalProxyFactory() != null) 334 { 335 final EJBLocalObject ejbObject = container.getLocalProxyFactory().getEntityEJBLocalObject(relatedId); 336 ejbObject.remove(); 337 } 338 else 339 { 340 final EJBObject ejbObject = (EJBObject )container.getProxyFactory().getEntityEJBObject(relatedId); 341 ejbObject.remove(); 342 } 343 } 344 345 interface SecurityActions 346 { 347 class UTIL 348 { 349 static SecurityActions getSecurityActions() 350 { 351 return System.getSecurityManager() == null ? NON_PRIVILEGED : PRIVILEGED; 352 } 353 } 354 355 SecurityActions NON_PRIVILEGED = new SecurityActions() 356 { 357 public Principal getPrincipal() 358 { 359 return SecurityAssociation.getPrincipal(); 360 } 361 362 public Object getCredential() 363 { 364 return SecurityAssociation.getCredential(); 365 } 366 }; 367 368 SecurityActions PRIVILEGED = new SecurityActions() 369 { 370 private final PrivilegedAction getPrincipalAction = new PrivilegedAction () 371 { 372 public Object run() 373 { 374 return SecurityAssociation.getPrincipal(); 375 } 376 }; 377 378 private final PrivilegedAction getCredentialAction = new PrivilegedAction () 379 { 380 public Object run() 381 { 382 return SecurityAssociation.getCredential(); 383 } 384 }; 385 386 public Principal getPrincipal() 387 { 388 return (Principal )AccessController.doPrivileged(getPrincipalAction); 389 } 390 391 public Object getCredential() 392 { 393 return AccessController.doPrivileged(getCredentialAction); 394 } 395 }; 396 397 Principal getPrincipal(); 398 399 Object getCredential(); 400 } 401 } 402 | Popular Tags |