KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ejb > plugins > cmp > jdbc > CascadeDeleteStrategy


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

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 JavaDoc;
34 import javax.ejb.EJBObject JavaDoc;
35 import javax.ejb.EJBLocalObject JavaDoc;
36 import java.util.List JavaDoc;
37 import java.util.ArrayList JavaDoc;
38 import java.util.Map JavaDoc;
39 import java.util.HashMap JavaDoc;
40 import java.sql.Connection JavaDoc;
41 import java.sql.PreparedStatement JavaDoc;
42 import java.security.PrivilegedAction JavaDoc;
43 import java.security.Principal JavaDoc;
44 import java.security.AccessController JavaDoc;
45 import java.rmi.RemoteException JavaDoc;
46
47 /**
48  *
49  * @author <a HREF="mailto:alex@jboss.org">Alexey Loubyansky</a>
50  * @version $Revision: 37459 $
51  */

52 public abstract class CascadeDeleteStrategy
53 {
54    /**
55     * No cascade-delete strategy.
56     */

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 JavaDoc[] oldRelationRefs, List JavaDoc ids)
66       {
67          cmrField.setInstanceValue(ctx, null);
68       }
69
70       public void cascadeDelete(EntityEnterpriseContext ctx, List JavaDoc oldValues) throws RemoveException JavaDoc, RemoteException JavaDoc
71       {
72          boolean trace = log.isTraceEnabled();
73          for(int i = 0; i < oldValues.size(); ++i)
74          {
75             Object JavaDoc 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    /**
94     * Specification compliant cascade-delete strategy, i.e. one DELETE per child
95     */

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 JavaDoc[] oldRelationRef, List JavaDoc ids)
105       {
106          cmrField.scheduleChildrenForCascadeDelete(ctx);
107          scheduleCascadeDelete(oldRelationRef, new ArrayList JavaDoc(ids));
108          cmrField.setInstanceValue(ctx, null);
109       }
110
111       public void cascadeDelete(EntityEnterpriseContext ctx, List JavaDoc oldValues) throws RemoveException JavaDoc, RemoteException JavaDoc
112       {
113          boolean trace = log.isTraceEnabled();
114          for(int i = 0; i < oldValues.size(); ++i)
115          {
116             Object JavaDoc 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    /**
134     * Batch cascade-delete strategy. Deletes children with one statement of the form
135     * DELETE FROM RELATED_TABLE WHERE FOREIGN_KEY = ?
136     */

137    public static final class BatchCascadeDeleteStrategy
138       extends CascadeDeleteStrategy
139    {
140       private final String JavaDoc 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 JavaDoc buf = new StringBuffer JavaDoc(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 JavaDoc[] oldRelationRefs, List JavaDoc ids)
171       {
172          cmrField.scheduleChildrenForBatchCascadeDelete(ctx);
173          scheduleCascadeDelete(oldRelationRefs, new ArrayList JavaDoc(ids));
174       }
175
176       public void cascadeDelete(EntityEnterpriseContext ctx, List JavaDoc oldValues) throws RemoveException JavaDoc, RemoteException JavaDoc
177       {
178          boolean didDelete = false;
179          boolean trace = log.isTraceEnabled();
180          for(int i = 0; i < oldValues.size(); ++i)
181          {
182             Object JavaDoc 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 JavaDoc[] oldRelationRefs, List JavaDoc ids);
240
241    public abstract void cascadeDelete(EntityEnterpriseContext ctx, List JavaDoc oldValues) throws RemoveException JavaDoc,
242       RemoteException JavaDoc;
243
244    protected void scheduleCascadeDelete(Object JavaDoc[] oldRelationsRef, List JavaDoc values)
245    {
246       Map JavaDoc oldRelations = (Map JavaDoc)oldRelationsRef[0];
247       if(oldRelations == null)
248       {
249          oldRelations = new HashMap JavaDoc();
250          oldRelationsRef[0] = oldRelations;
251       }
252       oldRelations.put(cmrField, values);
253       relatedManager.scheduleCascadeDelete(values);
254    }
255
256    protected void executeDeleteSQL(String JavaDoc sql, Object JavaDoc key) throws RemoveException JavaDoc
257    {
258       Connection JavaDoc con = null;
259       PreparedStatement JavaDoc ps = null;
260       int rowsAffected = 0;
261       try
262       {
263          if(log.isDebugEnabled())
264             log.debug("Executing SQL: " + sql);
265
266          // get the connection
267
con = entity.getDataSource().getConnection();
268          ps = con.prepareStatement(sql);
269
270          // set the parameters
271
entity.setPrimaryKeyParameters(ps, 1, key);
272
273          // execute statement
274
rowsAffected = ps.executeUpdate();
275       }
276       catch(Exception JavaDoc e)
277       {
278          log.error("Could not remove " + key, e);
279          throw new RemoveException JavaDoc("Could not remove " + key);
280       }
281       finally
282       {
283          JDBCUtil.safeClose(ps);
284          JDBCUtil.safeClose(con);
285       }
286
287       // check results
288
if(rowsAffected == 0)
289       {
290          log.error("Could not remove entity " + key);
291          throw new RemoveException JavaDoc("Could not remove entity");
292       }
293
294       if(log.isDebugEnabled())
295          log.debug("Remove: Rows affected = " + rowsAffected);
296    }
297
298    public void invokeRemoveRelated(Object JavaDoc relatedId) throws RemoveException JavaDoc, RemoteException JavaDoc
299    {
300       EntityContainer container = relatedManager.getContainer();
301
302       /*
303       try
304       {
305          EntityCache instanceCache = (EntityCache) container.getInstanceCache();
306          SecurityActions actions = SecurityActions.UTIL.getSecurityActions();
307
308          org.jboss.invocation.Invocation invocation = new org.jboss.invocation.Invocation();
309          invocation.setId(instanceCache.createCacheKey(relatedId));
310          invocation.setArguments(new Object[]{});
311          invocation.setTransaction(container.getTransactionManager().getTransaction());
312          invocation.setPrincipal(actions.getPrincipal());
313          invocation.setCredential(actions.getCredential());
314          invocation.setType(invocationType);
315          invocation.setMethod(removeMethod);
316
317          container.invoke(invocation);
318       }
319       catch(EJBException e)
320       {
321          throw e;
322       }
323       catch(Exception e)
324       {
325          throw new EJBException("Error in remove instance", e);
326       }
327       */

328
329       /**
330        * Have to remove through EJB[Local}Object interface since the proxy contains the 'removed' flag
331        * to be set on removal.
332        */

333       if(container.getLocalProxyFactory() != null)
334       {
335          final EJBLocalObject JavaDoc ejbObject = container.getLocalProxyFactory().getEntityEJBLocalObject(relatedId);
336          ejbObject.remove();
337       }
338       else
339       {
340          final EJBObject JavaDoc ejbObject = (EJBObject JavaDoc)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 JavaDoc getPrincipal()
358          {
359             return SecurityAssociation.getPrincipal();
360          }
361
362          public Object JavaDoc getCredential()
363          {
364             return SecurityAssociation.getCredential();
365          }
366       };
367
368       SecurityActions PRIVILEGED = new SecurityActions()
369       {
370          private final PrivilegedAction JavaDoc getPrincipalAction = new PrivilegedAction JavaDoc()
371          {
372             public Object JavaDoc run()
373             {
374                return SecurityAssociation.getPrincipal();
375             }
376          };
377
378          private final PrivilegedAction JavaDoc getCredentialAction = new PrivilegedAction JavaDoc()
379          {
380             public Object JavaDoc run()
381             {
382                return SecurityAssociation.getCredential();
383             }
384          };
385
386          public Principal JavaDoc getPrincipal()
387          {
388             return (Principal JavaDoc)AccessController.doPrivileged(getPrincipalAction);
389          }
390
391          public Object JavaDoc getCredential()
392          {
393             return AccessController.doPrivileged(getCredentialAction);
394          }
395       };
396
397       Principal JavaDoc getPrincipal();
398
399       Object JavaDoc getCredential();
400    }
401 }
402
Popular Tags