KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > amber > table > LinkColumns


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  * Free Software Foundation, Inc.
23  * 59 Temple Place, Suite 330
24  * Boston, MA 02111-1307 USA
25  *
26  * @author Scott Ferguson
27  */

28
29 package com.caucho.amber.table;
30
31 import com.caucho.amber.entity.AmberCompletion;
32 import com.caucho.amber.entity.Entity;
33 import com.caucho.amber.manager.AmberConnection;
34 import com.caucho.amber.type.EntityType;
35 import com.caucho.util.CharBuffer;
36 import com.caucho.util.L10N;
37 import com.caucho.util.Log;
38
39 import java.sql.PreparedStatement JavaDoc;
40 import java.sql.ResultSet JavaDoc;
41 import java.sql.SQLException JavaDoc;
42 import java.util.ArrayList JavaDoc;
43 import java.util.logging.Logger JavaDoc;
44
45 /**
46  * Represents a many-to-one link from one table to another.
47  */

48 public class LinkColumns {
49   private static final L10N L = new L10N(LinkColumns.class);
50   private static final Logger JavaDoc log = Log.open(LinkColumns.class);
51
52   private static final int NO_CASCADE_DELETE = 0;
53   private static final int SOURCE_CASCADE_DELETE = 1;
54   private static final int TARGET_CASCADE_DELETE = 2;
55
56   private Table _sourceTable;
57   private Table _targetTable;
58
59   private ArrayList JavaDoc<ForeignColumn> _columns;
60
61   private int _cascadeDelete;
62
63   private AmberCompletion _tableDeleteCompletion;
64   private AmberCompletion _tableUpdateCompletion;
65
66   /**
67    * Creates the table link.
68    */

69   public LinkColumns(Table sourceTable, Table targetTable,
70                      ArrayList JavaDoc<ForeignColumn> columns)
71   {
72     _sourceTable = sourceTable;
73     _targetTable = targetTable;
74
75     _columns = columns;
76
77     _tableDeleteCompletion = sourceTable.getDeleteCompletion();
78     _tableUpdateCompletion = sourceTable.getUpdateCompletion();
79
80     _sourceTable.addOutgoingLink(this);
81     _targetTable.addIncomingLink(this);
82   }
83
84   /**
85    * Sets the cascade-delete of the source when the target is deleted,
86    * i.e. a one-to-many cascaded delete like an identifying relation.
87    */

88   public void setSourceCascadeDelete(boolean isCascadeDelete)
89   {
90     if (isCascadeDelete) {
91       assert(_cascadeDelete != TARGET_CASCADE_DELETE);
92
93       _cascadeDelete = SOURCE_CASCADE_DELETE;
94     }
95     else if (_cascadeDelete == SOURCE_CASCADE_DELETE)
96       _cascadeDelete = NO_CASCADE_DELETE;
97   }
98
99   /**
100    * Sets the cascade-delete of the target when the source is deleted.
101    */

102   public void setTargetCascadeDelete(boolean isCascadeDelete)
103   {
104     if (isCascadeDelete) {
105       assert(_cascadeDelete != SOURCE_CASCADE_DELETE);
106
107       _cascadeDelete = TARGET_CASCADE_DELETE;
108     }
109     else if (_cascadeDelete == TARGET_CASCADE_DELETE)
110       _cascadeDelete = NO_CASCADE_DELETE;
111   }
112
113   /**
114    * Return true if the source is deleted when the target is deleted.
115    */

116   public boolean isSourceCascadeDelete()
117   {
118     return _cascadeDelete == SOURCE_CASCADE_DELETE;
119   }
120
121   /**
122    * Return true if the source is deleted when the target is deleted.
123    */

124   public boolean isTargetCascadeDelete()
125   {
126     return _cascadeDelete == TARGET_CASCADE_DELETE;
127   }
128
129   /**
130    * Returns the source table.
131    */

132   public Table getSourceTable()
133   {
134     return _sourceTable;
135   }
136
137   /**
138    * Returns the target table.
139    */

140   public Table getTargetTable()
141   {
142     return _targetTable;
143   }
144
145   /**
146    * Returns the component list.
147    */

148   public ArrayList JavaDoc<ForeignColumn> getColumns()
149   {
150     return _columns;
151   }
152
153   /**
154    * Returns the sql column for the source corresponding to the target key.
155    */

156
157   /**
158    * Generates the linking for a link
159    */

160   public ForeignColumn getSourceColumn(Column targetKey)
161   {
162     for (int i = _columns.size() - 1; i >= 0; i--) {
163       ForeignColumn column = _columns.get(i);
164
165       if (column.getTargetColumn() == targetKey)
166         return column;
167     }
168
169
170     return null;
171   }
172
173   /**
174    * Generates SQL select.
175    */

176   public String JavaDoc generateSelectSQL(String JavaDoc table)
177   {
178     CharBuffer cb = new CharBuffer();
179
180     for (int i = 0; i < _columns.size(); i++) {
181       if (i != 0)
182         cb.append(", ");
183
184       if (table != null) {
185         cb.append(table);
186         cb.append(".");
187       }
188
189       cb.append(_columns.get(i).getName());
190     }
191
192     return cb.toString();
193   }
194
195   /**
196    * Generates SQL insert.
197    */

198   public void generateInsert(ArrayList JavaDoc<String JavaDoc> columns)
199   {
200     for (int i = 0; i < _columns.size(); i++)
201       columns.add(_columns.get(i).getName());
202   }
203
204   /**
205    * Generates SQL select.
206    */

207   public String JavaDoc generateUpdateSQL()
208   {
209     CharBuffer cb = new CharBuffer();
210
211     for (int i = 0; i < _columns.size(); i++) {
212       if (i != 0)
213         cb.append(", ");
214
215       cb.append(_columns.get(i).getName() + "=?");
216     }
217
218     return cb.toString();
219   }
220
221   /**
222    * Generates SQL match.
223    */

224   public String JavaDoc generateMatchArgSQL(String JavaDoc table)
225   {
226     CharBuffer cb = new CharBuffer();
227
228     for (int i = 0; i < _columns.size(); i++) {
229       if (i != 0)
230         cb.append(" and ");
231
232       if (table != null) {
233         cb.append(table);
234         cb.append(".");
235       }
236
237       cb.append(_columns.get(i).getName());
238       cb.append("=?");
239     }
240
241     return cb.toString();
242   }
243
244   /**
245    * Generates the linking for a join
246    *
247    * @param sourceTable the SQL table name for the source
248    * @param targetTable the SQL table name for the target
249    */

250   public String JavaDoc generateJoin(String JavaDoc sourceTable,
251                              String JavaDoc targetTable)
252   {
253     return generateJoin(sourceTable, targetTable, false);
254   }
255
256   /**
257    * Generates the linking for a join
258    *
259    * @param sourceTable the SQL table name for the source
260    * @param targetTable the SQL table name for the target
261    * @param isArg true if targetTable is an argument "?"
262    */

263   public String JavaDoc generateJoin(String JavaDoc sourceTable,
264                              String JavaDoc targetTable,
265                              boolean isArg)
266   {
267     CharBuffer cb = new CharBuffer();
268
269     cb.append('(');
270
271     for (int i = 0; i < _columns.size(); i++) {
272       ForeignColumn column = _columns.get(i);
273
274       if (i != 0)
275         cb.append(" and ");
276
277       cb.append(sourceTable);
278       cb.append('.');
279       cb.append(column.getName());
280
281       cb.append(" = ");
282
283       cb.append(targetTable);
284
285       if (isArg)
286         continue;
287
288       cb.append('.');
289       cb.append(column.getTargetColumn().getName());
290     }
291
292     cb.append(')');
293
294     return cb.toString();
295   }
296
297   /**
298    * Generates the many-to-many linking.
299    * This join is the one-to-many join and the other
300    * join is passed in as an argument used to link
301    * the two source tables that are pointing to the
302    * same target table.
303    *
304    * @param join the many-to-one join
305    * @param sourceTable1 the SQL table name for the 1st source
306    * @param sourceTable2 the SQL table name for the 2nd source
307    */

308   public String JavaDoc generateJoin(LinkColumns manyToOneJoin,
309                              String JavaDoc sourceTable1,
310                              String JavaDoc sourceTable2)
311   {
312     // Implemented for jpa/10cb
313

314     if (manyToOneJoin._columns.size() != _columns.size())
315       return "";
316
317     CharBuffer cb = new CharBuffer();
318
319     cb.append('(');
320
321     for (int i = 0; i < _columns.size(); i++) {
322       ForeignColumn column = _columns.get(i);
323       ForeignColumn otherColumn = manyToOneJoin._columns.get(i);
324
325       if (i != 0)
326         cb.append(" and ");
327
328       cb.append(sourceTable1);
329       cb.append('.');
330       cb.append(column.getName());
331
332       cb.append(" = ");
333
334       cb.append(sourceTable2);
335
336       cb.append('.');
337       cb.append(otherColumn.getName());
338     }
339
340     cb.append(')');
341
342     return cb.toString();
343   }
344
345   /**
346    * Generates the linking for a where clause
347    *
348    * @param sourceTable the SQL table name for the source
349    * @param targetTable the SQL table name for the target
350    */

351   public String JavaDoc generateWhere(String JavaDoc sourceTable,
352                               String JavaDoc targetTable)
353   {
354     CharBuffer cb = new CharBuffer();
355
356     cb.append('(');
357
358     for (int i = 0; i < _columns.size(); i++) {
359       ForeignColumn column = _columns.get(i);
360
361       if (i != 0)
362         cb.append(" and ");
363
364       if (! column.isNotNull()) {
365
366         if (sourceTable == null)
367           cb.append('?');
368         else {
369           cb.append(sourceTable);
370           cb.append('.');
371           cb.append(column.getName());
372         }
373
374         cb.append(" is not null ");
375       }
376
377       cb.append(" and ");
378
379       // jpa/10c9
380
if (sourceTable == null) {
381         cb.append('?');
382       }
383       else {
384         cb.append(sourceTable);
385         cb.append('.');
386         cb.append(column.getName());
387       }
388
389       cb.append(" = ");
390
391       cb.append(targetTable);
392       cb.append('.');
393       cb.append(column.getTargetColumn().getName());
394     }
395
396     cb.append(')');
397
398     return cb.toString();
399   }
400
401   /**
402    * Cleans up any fields from a delete.
403    */

404   public void beforeTargetDelete(AmberConnection aConn, Entity entity)
405     throws SQLException JavaDoc
406   {
407     // commented out: jpa/0h25
408
// aConn.flushNoChecks();
409

410     String JavaDoc sourceTable = _sourceTable.getName();
411
412     if (! isSourceCascadeDelete()) {
413       CharBuffer cb = new CharBuffer();
414
415       cb.append("update " + sourceTable + " set ");
416
417       ArrayList JavaDoc<ForeignColumn> columns = getColumns();
418
419       for (int i = 0; i < columns.size(); i++) {
420         if (i != 0)
421           cb.append (", ");
422
423         cb.append(columns.get(i).getName() + "=null");
424       }
425
426       cb.append(" where ");
427
428       for (int i = 0; i < columns.size(); i++) {
429         if (i != 0)
430           cb.append (" and ");
431
432         cb.append(columns.get(i).getName() + "=?");
433       }
434
435       PreparedStatement JavaDoc pstmt = aConn.prepareStatement(cb.toString());
436
437       entity.__caucho_setKey(pstmt, 1);
438
439       pstmt.executeUpdate();
440
441       aConn.addCompletion(_sourceTable.getUpdateCompletion());
442     }
443     else if (_sourceTable.isCascadeDelete()) {
444       // if the link cascades deletes to the source and the source
445
// table also has cascade deletes, then we need to load the
446
// target entities and delete them recursively
447
//
448
// in theory, this could cause a loop, but we're ignoring that
449
// case for now
450

451       EntityType entityType = (EntityType) _sourceTable.getType();
452
453       CharBuffer cb = new CharBuffer();
454
455       cb.append("select ");
456       cb.append(entityType.getId().generateSelect("o"));
457       cb.append(" from " + sourceTable + " o");
458       cb.append(" where ");
459
460       ArrayList JavaDoc<ForeignColumn> columns = getColumns();
461
462       for (int i = 0; i < columns.size(); i++) {
463         if (i != 0)
464           cb.append (" and ");
465
466         cb.append(columns.get(i).getName() + "=?");
467       }
468
469       PreparedStatement JavaDoc pstmt = aConn.prepareStatement(cb.toString());
470
471       entity.__caucho_setKey(pstmt, 1);
472
473       ArrayList JavaDoc<Object JavaDoc> proxyList = new ArrayList JavaDoc<Object JavaDoc>();
474
475       ResultSet JavaDoc rs = pstmt.executeQuery();
476       while (rs.next()) {
477         proxyList.add(entityType.getHome().loadLazy(aConn, rs, 1));
478       }
479       rs.close();
480
481       for (Object JavaDoc obj : proxyList) {
482         entityType.getHome().getEntityFactory().delete(aConn, obj);
483       }
484     }
485     else {
486       CharBuffer cb = new CharBuffer();
487
488       cb.append("delete from " + sourceTable +
489                 " where ");
490
491       ArrayList JavaDoc<ForeignColumn> columns = getColumns();
492
493       for (int i = 0; i < columns.size(); i++) {
494         if (i != 0)
495           cb.append (" and ");
496
497         cb.append(columns.get(i).getName() + "=?");
498       }
499
500       PreparedStatement JavaDoc pstmt = aConn.prepareStatement(cb.toString());
501
502       entity.__caucho_setKey(pstmt, 1);
503
504       pstmt.executeUpdate();
505
506       aConn.addCompletion(_sourceTable.getDeleteCompletion());
507     }
508
509     aConn.expire();
510   }
511
512   /**
513    * Cleans up any fields from a delete.
514    */

515   public void afterSourceDelete(AmberConnection aConn, Entity entity)
516     throws SQLException JavaDoc
517   {
518     // this should be handled programmatically
519
}
520
521   public String JavaDoc toString()
522   {
523     return "[" + _sourceTable + ", " + _targetTable + ", " + _columns + "]";
524   }
525 }
526
Popular Tags