001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.amber.gen;
031:
032: import com.caucho.amber.table.LinkColumns;
033: import com.caucho.amber.table.Table;
034: import com.caucho.amber.type.*;
035: import com.caucho.bytecode.JMethod;
036: import com.caucho.java.JavaWriter;
037: import com.caucho.java.gen.ClassComponent;
038: import com.caucho.util.L10N;
039:
040: import java.io.IOException;
041: import java.util.ArrayList;
042:
043: /**
044: * Generates the Java code for the wrapped object.
045: */
046: public class LoadGroupGenerator extends ClassComponent {
047: private static final L10N L = new L10N(LoadGroupGenerator.class);
048:
049: private String _extClassName;
050: private RelatedType _relatedType;
051: private int _index;
052:
053: public LoadGroupGenerator(String extClassName,
054: RelatedType relatedType, int index) {
055: _extClassName = extClassName;
056: _relatedType = relatedType;
057: _index = index;
058: }
059:
060: /**
061: * Generates the load group.
062: */
063: public void generate(JavaWriter out) throws IOException {
064: out.println();
065: out.println("protected void __caucho_load_" + _index
066: + "(com.caucho.amber.manager.AmberConnection aConn)");
067: out.println("{");
068: out.pushDepth();
069:
070: int group = _index / 64;
071: long mask = (1L << (_index % 64));
072:
073: out.println("boolean isLoaded = (__caucho_loadMask_" + group
074: + " & " + mask + "L) != 0;");
075:
076: // jpa/0ge2: MappedSuperclassType
077: if (_relatedType.getTable() != null) {
078:
079: int min = 0;
080:
081: if (_relatedType.getParentType() == null)
082: min = _index;
083:
084: // XXX: need to do another check for a long hierarchy and/or many-to-one
085: // if ((_relatedType.getParentType() != null) &&
086: // (_index = _relatedType.getParentType().getLoadGroupIndex() + 1)) {
087: // min = _relatedType.getParentType().getLoadGroupIndex();
088: // }
089:
090: int max = _index;
091:
092: generateTransactionChecks(out, group, mask, min, max);
093:
094: if (min <= max) {
095: out.println("else {");
096: out.pushDepth();
097: }
098:
099: for (int i = min; i <= max; i++) {
100: // jpa/0l48: inheritance optimization.
101: out.println("if ((__caucho_loadMask_" + group + " & "
102: + (1L << (i % 64)) + "L) == 0)");
103: out.println(" __caucho_load_select_" + i + "(aConn);");
104: }
105:
106: if (min <= max) {
107: out.popDepth();
108: out.println("}");
109: }
110:
111: out.println();
112:
113: _relatedType.generatePostLoadSelect(out, 1, _index);
114:
115: if (min <= max) {
116: // jpa/0g0k: only makes transactional if exists.
117: out.println();
118: out.println("if ((__caucho_loadMask_0 & 1L) != 0) {");
119: out.println(" aConn.makeTransactional(this);");
120:
121: out.println("}");
122: }
123:
124: // jpa/0o09
125: // needs to be after load to prevent loop if toString() expects data
126: out.println();
127: out
128: .println("if (__caucho_log.isLoggable(java.util.logging.Level.FINER))");
129: out.println(" __caucho_log.finer(\"amber loaded-" + _index
130: + " \" + this.getClass().getName());");
131:
132: out.println("if (! isLoaded) {");
133: out.pushDepth();
134:
135: // ejb/06j2, ejb/0690
136: if (_relatedType.getHasLoadCallback() && _index == 0) {
137: out.println();
138: out.println("__caucho_load_callback();");
139: }
140:
141: // ejb/069a, jpa/0r00 vs. jpa/0r01
142: out.println();
143: out.println("if (__caucho_home != null)");
144: out.println(" __caucho_home.postLoad(this);");
145:
146: // jpa/0r01: @PostLoad, with transaction.
147: // Within a transaction the entity is not copied
148: // directly from cache, so we need to invoke the
149: // callbacks after load. For jpa/0r00, see AmberMappedComponent.
150: generateCallbacks(out, _relatedType.getPostLoadCallbacks());
151:
152: out.popDepth();
153: out.println("}");
154: }
155:
156: out.popDepth();
157: out.println("}");
158:
159: if (_index == 0 && _relatedType.getHasLoadCallback()) {
160: out.println();
161: out.println("protected void __caucho_load_callback() {}");
162: }
163:
164: generateLoadSelect(out, group, mask);
165: }
166:
167: private void generateTransactionChecks(JavaWriter out, int group,
168: long mask, int min, int max) throws IOException {
169: // non-read-only entities must be reread in a transaction
170: if (!_relatedType.isReadOnly()) {
171: // jpa/1800
172: out.println("if (aConn.isInTransaction()) {");
173: out.pushDepth();
174:
175: // deleted objects are not reloaded
176: out
177: .println("if (com.caucho.amber.entity.EntityState.P_DELETING.ordinal() <= __caucho_state.ordinal()) {");
178: out.println(" return;");
179: out.println("}");
180:
181: // from non-transactional to transactional
182: out
183: .println("else if (__caucho_state.ordinal() <= com.caucho.amber.entity.EntityState.P_NON_TRANSACTIONAL.ordinal()) {");
184: out.pushDepth();
185:
186: out
187: .println("com.caucho.amber.entity.EntityState state = __caucho_state;");
188:
189: out
190: .println("__caucho_state = com.caucho.amber.entity.EntityState.P_TRANSACTIONAL;");
191:
192: // XXX: ejb/0d01 (create issue?)
193: // jpa/0g0k: see __caucho_load_select
194: // out.println(" aConn.makeTransactional(this);");
195: // out.println(" if ((state > 0) && ((__caucho_loadMask_" + group + " & " + mask + "L) != 0))");
196: // out.println(" return;");
197: out.println();
198:
199: /* XXX: jpa/0o09
200: int loadCount = _relatedType.getLoadGroupIndex();
201: for (int i = 0; i <= loadCount / 64; i++) {
202: out.println(" __caucho_loadMask_" + i + " = 0;");
203: }
204: */
205:
206: int dirtyCount = _relatedType.getDirtyIndex();
207: for (int i = 0; i <= dirtyCount / 64; i++) {
208: out.println("__caucho_dirtyMask_" + i + " = 0;");
209: }
210:
211: out.popDepth();
212: out.println("}");
213: // ejb/0d01 - already loaded in the transaction
214: /*
215: out.println("else if ((__caucho_loadMask_" + group + " & " + mask + "L) != 0)");
216: out.println(" return;");
217: */
218:
219: for (int i = min; i <= max; i++) {
220: // jpa/0l48: inheritance optimization.
221: out.println();
222: out.println("if ((__caucho_loadMask_" + group + " & "
223: + (1L << (i % 64)) + "L) == 0)");
224: out.println(" __caucho_load_select_" + i + "(aConn);");
225: }
226:
227: out.popDepth();
228: out.println("}");
229: out.print("else ");
230: }
231:
232: out.println("if ((__caucho_loadMask_" + group + " & " + mask
233: + "L) != 0) {");
234: out.println("}");
235:
236: // XXX: the load doesn't cover other load groups
237: out.println("else if (__caucho_cacheItem != null) {");
238: out.pushDepth();
239: out.println(_extClassName + " item = (" + _extClassName
240: + ") __caucho_cacheItem.getEntity();");
241:
242: out.println("item.__caucho_load_select_" + _index + "(aConn);");
243:
244: /* XXX: ejb/06--, ejb/0a-- and jpa/0o04
245: out.println("try {");
246: out.pushDepth();
247:
248: // jpa/0o01
249: out.println("Object child;");
250: */
251:
252: // ejb/06--, ejb/0a-- and jpa/0o04
253: _relatedType.generateCopyLoadObject(out, "super", "item",
254: _index);
255:
256: // out.println("__caucho_loadMask_" + group + " |= " + mask + "L;");
257: //out.println("__caucho_loadMask_" + group + " |= item.__caucho_loadMask_" + group + ";"); // mask + "L;");
258:
259: out.println("__caucho_loadMask_" + group
260: + " |= item.__caucho_loadMask_" + group + " & " + mask
261: + "L;"); // mask + "L;");
262:
263: /* XXX: ejb/06--, ejb/0a-- and jpa/0o04
264: out.popDepth();
265: out.println("} catch (RuntimeException e) {");
266: out.println(" throw e;");
267: out.println("} catch (Exception e) {");
268: out.println(" throw new com.caucho.amber.AmberRuntimeException(e);");
269: out.println("}");
270:
271: out.println();
272: out.println("return;");
273: */
274:
275: out.popDepth();
276: out.println("}");
277: }
278:
279: private void generateLoadSelect(JavaWriter out, int group, long mask)
280: throws IOException {
281: // jpa/0l40
282: if ((_index == 0) && (_relatedType.getDiscriminator() != null)) {
283: out.println();
284: out.println("String __caucho_discriminator;");
285: }
286:
287: out.println();
288: out.println("protected void __caucho_load_select_" + _index
289: + "(com.caucho.amber.manager.AmberConnection aConn)");
290: out.println("{");
291: out.pushDepth();
292:
293: if (_relatedType.getTable() == null) {
294: out.popDepth();
295: out.println("}");
296:
297: return;
298: }
299:
300: out.println("if ((__caucho_loadMask_" + group + " & " + mask
301: + "L) != 0)");
302: out.println(" return;");
303:
304: Table table = _relatedType.getTable();
305:
306: String from = null;
307: String select = null;
308: String where = null;
309:
310: String subSelect = null;
311: Table mainTable = null;
312: String tableName = null;
313:
314: select = _relatedType.generateLoadSelect(table, "o", _index);
315:
316: if (select != null) {
317: from = table.getName() + " o";
318: where = _relatedType.getId().generateMatchArgWhere("o");
319: mainTable = table;
320: tableName = "o";
321: }
322:
323: ArrayList<Table> subTables = _relatedType.getSecondaryTables();
324:
325: for (int i = 0; i < subTables.size(); i++) {
326: Table subTable = subTables.get(i);
327:
328: subSelect = _relatedType.generateLoadSelect(subTable, "o"
329: + i, _index);
330:
331: if (subSelect == null)
332: continue;
333:
334: if (select != null)
335: select = select + ", " + subSelect;
336: else
337: select = subSelect;
338:
339: if (from != null)
340: from = from + ", " + subTable.getName() + " o" + i;
341: else
342: from = subTable.getName() + " o" + i;
343:
344: if (where != null) {
345: LinkColumns link = subTable.getDependentIdLink();
346:
347: where = where + " and "
348: + link.generateJoin("o" + i, "o");
349: } else
350: throw new IllegalStateException();
351: }
352:
353: if (select == null) {
354: if (_index > 0) {
355: // XXX: jpa/0o00
356:
357: out.println("return;");
358:
359: out.popDepth();
360: out.println("}");
361:
362: return;
363: }
364:
365: select = "1";
366: }
367:
368: if (where == null) {
369: from = table.getName() + " o";
370:
371: where = _relatedType.getId().generateMatchArgWhere("o");
372: }
373:
374: String sql = "select " + select + " from " + from + " where "
375: + where;
376:
377: out.println("java.sql.ResultSet rs = null;");
378: out.println();
379:
380: out.println("try {");
381: out.pushDepth();
382:
383: // jpa/0o05
384: out
385: .println("com.caucho.amber.entity.Entity contextEntity = aConn.getEntity(this);");
386:
387: out.println();
388: out.print("String sql = \"");
389: out.printJavaString(sql);
390: out.println("\";");
391:
392: out.println();
393: out
394: .println("java.sql.PreparedStatement pstmt = aConn.prepareStatement(sql);");
395:
396: out.println("int index = 1;");
397: _relatedType.getId()
398: .generateSet(out, "pstmt", "index", "super");
399:
400: out.println();
401: out.println("rs = pstmt.executeQuery();");
402:
403: out.println("if (rs.next()) {");
404: out.pushDepth();
405:
406: // jpa/0l40
407: if ((_index == 0) && (_relatedType.getDiscriminator() != null)) {
408: out.println();
409: out.println("__caucho_discriminator = rs.getString(1);");
410: }
411:
412: // jpa/0gg3
413: _relatedType.generateLoad(out, "rs", "", 1, _index, null);
414: out
415: .println("__caucho_loadMask_" + group + " |= " + mask
416: + "L;");
417:
418: out.popDepth();
419: out.println("}");
420: out.println("else {");
421: out.println(" rs.close();");
422:
423: String errorString = ("(\"amber load: no matching object "
424: + _relatedType.getName() + "[\" + __caucho_getPrimaryKey() + \"]\")");
425:
426: out
427: .println(" throw new com.caucho.amber.AmberObjectNotFoundException("
428: + errorString + ");");
429: out.println("}");
430:
431: out.popDepth();
432: out.println("} catch (RuntimeException e) {");
433: out.println(" throw e;");
434: out.println("} catch (Exception e) {");
435: out
436: .println(" throw new com.caucho.amber.AmberRuntimeException(e);");
437: out.println("} finally {");
438: out.println(" aConn.close(rs);");
439: out.println("}");
440:
441: out.popDepth();
442: out.println("}");
443: }
444:
445: private void generateCallbacks(JavaWriter out,
446: ArrayList<JMethod> callbacks) throws IOException {
447: if (callbacks.size() == 0)
448: return;
449:
450: out.println();
451: for (JMethod method : callbacks) {
452: out.println(method.getName() + "();");
453: }
454: }
455: }
|