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.field;
031:
032: import com.caucho.amber.manager.AmberPersistenceUnit;
033: import com.caucho.amber.table.Column;
034: import com.caucho.amber.type.AbstractStatefulType;
035: import com.caucho.amber.type.EmbeddableType;
036: import com.caucho.amber.type.PrimitiveType;
037: import com.caucho.amber.type.RelatedType;
038: import com.caucho.amber.type.Type;
039: import com.caucho.bytecode.JClass;
040: import com.caucho.bytecode.JMethod;
041: import com.caucho.java.JavaWriter;
042: import com.caucho.log.Log;
043: import com.caucho.util.CharBuffer;
044: import com.caucho.util.L10N;
045:
046: import java.io.IOException;
047: import java.util.ArrayList;
048: import java.util.HashSet;
049: import java.util.logging.Logger;
050:
051: /**
052: * Configuration for a bean's field
053: */
054: public class CompositeId extends Id {
055: private static final L10N L = new L10N(CompositeId.class);
056: protected static final Logger log = Log.open(CompositeId.class);
057:
058: private JClass _keyClass;
059:
060: public CompositeId(RelatedType ownerType, ArrayList<IdField> keys) {
061: super (ownerType, keys);
062: }
063:
064: protected CompositeId(RelatedType ownerType) {
065: super (ownerType);
066: }
067:
068: /**
069: * Sets the foreign key type.
070: */
071: public void setKeyClass(JClass keyClass) {
072: _keyClass = keyClass;
073:
074: getOwnerType().addDependency(keyClass);
075: }
076:
077: /**
078: * Returns the foreign type.
079: */
080: public String getForeignTypeName() {
081: if (_keyClass != null)
082: return _keyClass.getName();
083: else if (isEmbeddedId())
084: return getEmbeddedIdField().getJavaTypeName();
085: else
086: return getOwnerType().getName();
087: }
088:
089: /**
090: * Returns the foreign type.
091: */
092: public String getForeignMakeKeyName() {
093: return getOwnerType().getName().replace('.', '_').replace('/',
094: '_');
095: }
096:
097: /**
098: * Generates any prologue.
099: */
100: public void generatePrologue(JavaWriter out,
101: HashSet<Object> completedSet) throws IOException {
102: super .generatePrologue(out, completedSet);
103:
104: generatePrologue(out, completedSet, getForeignMakeKeyName());
105: }
106:
107: /**
108: * Generates any prologue.
109: */
110: public void generatePrologue(JavaWriter out,
111: HashSet<Object> completedSet, String name)
112: throws IOException {
113: // jpa/0u21
114: out.println();
115: out.println("private transient " + getForeignTypeName()
116: + " __caucho_compound_key = new "
117: + getForeignTypeName() + "();");
118:
119: generatePrologueMake(out, completedSet);
120: generatePrologueLoad(out, completedSet);
121: }
122:
123: /**
124: * Generates any prologue.
125: */
126: public void generatePrologueMake(JavaWriter out,
127: HashSet<Object> completedSet) throws IOException {
128: String makeName = "__caucho_make_key_"
129: + getForeignMakeKeyName();
130:
131: if (completedSet.contains(makeName))
132: return;
133:
134: completedSet.add(makeName);
135:
136: out.println();
137: out.print("private static ");
138: out.print(getForeignTypeName() + " " + makeName);
139: out.print("(");
140:
141: if (!isEmbeddedId()) {
142: ArrayList<IdField> keys = getKeys();
143: for (int i = 0; i < keys.size(); i++) {
144: if (i != 0)
145: out.print(", ");
146:
147: IdField key = keys.get(i);
148:
149: out.print(key.getJavaTypeName() + " a" + i);
150: }
151: } else {
152: EmbeddableType embeddable = (EmbeddableType) getEmbeddedIdField()
153: .getType();
154:
155: ArrayList<AmberField> fields = embeddable.getFields();
156: for (int i = 0; i < fields.size(); i++) {
157: if (i != 0)
158: out.print(", ");
159:
160: AmberField field = fields.get(i);
161:
162: out.print(field.getJavaTypeName() + " a" + i);
163: }
164: }
165:
166: out.println(")");
167: out.println("{");
168: out.pushDepth();
169:
170: out.println();
171: out.println(getForeignTypeName() + " key = new "
172: + getForeignTypeName() + "();");
173:
174: if (getOwnerType().getPersistenceUnit().isJPA()
175: && !isEmbeddedId()) {
176: String args = "";
177:
178: ArrayList<IdField> keys = getKeys();
179:
180: for (int i = 0; i < keys.size(); i++) {
181: KeyPropertyField key = (KeyPropertyField) keys.get(i);
182:
183: String name = key.getName();
184:
185: char ch = Character.toUpperCase(name.charAt(0));
186: if (name.length() == 1)
187: name = "get" + ch;
188: else
189: name = "get" + ch + key.getName().substring(1);
190:
191: JMethod method = AbstractStatefulType.getGetter(
192: _keyClass, name);
193:
194: if (key.isKeyField() || (method != null)) {
195: out.println(key.generateSetKeyProperty("key", "a"
196: + i)
197: + ";");
198: } else {
199: // Arg. constructor jpa/0u21
200: if (i != 0)
201: args += ", ";
202:
203: args += " a" + i;
204:
205: out.println("if (a" + i + " == null)");
206: out.println(" return new " + getForeignTypeName()
207: + "();");
208:
209: if (i + 1 == keys.size())
210: out.print("key = new " + getForeignTypeName()
211: + "(" + args + ");");
212: }
213: }
214:
215: } else {
216: ArrayList fields;
217:
218: if (getEmbeddedIdField() == null) {
219: // ejb/06x2
220: fields = getKeys();
221: } else {
222: EmbeddableType embeddable = (EmbeddableType) getEmbeddedIdField()
223: .getType();
224:
225: fields = embeddable.getFields();
226: }
227:
228: for (int i = 0; i < fields.size(); i++) {
229: AmberField field = (AmberField) fields.get(i);
230:
231: if (getOwnerType().isFieldAccess())
232: out
233: .println(field.generateSet("key", "a" + i)
234: + ";");
235: else {
236: String setter = field.getName();
237:
238: if (getOwnerType().getPersistenceUnit().isJPA()) {
239: setter = "set"
240: + Character.toUpperCase(setter
241: .charAt(0))
242: + (setter.length() == 1 ? "" : setter
243: .substring(1));
244:
245: out.println("key." + setter + "(a" + i + ");");
246: } else
247: // XXX: ejb/06x2, ejb/06if
248: out.println("key." + setter + " = a" + i + ";");
249: }
250: }
251: }
252:
253: out.println("return key;");
254:
255: out.popDepth();
256: out.println("}");
257: }
258:
259: /**
260: * Generates any prologue.
261: */
262: public void generatePrologueLoad(JavaWriter out,
263: HashSet<Object> completedSet) throws IOException {
264: String loadName = "__caucho_load_key_"
265: + getForeignMakeKeyName();
266:
267: if (completedSet.contains(loadName))
268: return;
269:
270: completedSet.add(loadName);
271:
272: out.println();
273: out.print("private static ");
274: out.print(getForeignTypeName() + " " + loadName);
275: out
276: .println("(com.caucho.amber.manager.AmberConnection aConn, java.sql.ResultSet rs, int index)");
277: out.println(" throws java.sql.SQLException");
278:
279: out.println("{");
280: out.pushDepth();
281:
282: int index = 0;
283: ArrayList<IdField> keys = getKeys();
284: for (int i = 0; i < keys.size(); i++) {
285: IdField key = keys.get(i);
286:
287: String javaType = key.getJavaTypeName();
288: out.print(javaType + " a" + i + " = (" + javaType + ") ");
289: index = key.getType().generateLoad(out, "rs", "index",
290: index);
291: out.println(";");
292:
293: out.println("if (rs.wasNull())");
294: out.println(" return null;");
295: }
296:
297: out.print(getForeignTypeName() + " key = new "
298: + getForeignTypeName() + "(");
299:
300: if (isEmbeddedId()
301: || !getOwnerType().getPersistenceUnit().isJPA()) {
302: out.println(");");
303:
304: // ejb/06x2
305: for (int i = 0; i < keys.size(); i++) {
306: out.println(keys.get(i).generateSetKeyProperty("key",
307: "a" + i)
308: + ";");
309: }
310: } else {
311: for (int i = 0; i < keys.size(); i++) {
312: KeyPropertyField key = (KeyPropertyField) keys.get(i);
313:
314: String name = key.getName();
315:
316: char ch = Character.toUpperCase(name.charAt(0));
317: if (name.length() == 1)
318: name = "get" + ch;
319: else
320: name = "get" + ch + key.getName().substring(1);
321:
322: JMethod method = AbstractStatefulType.getGetter(
323: _keyClass, name);
324:
325: if (key.isKeyField() || (method != null)) {
326: if (i == 0)
327: out.println(");");
328:
329: out.println(key.generateSetKeyProperty("key", "a"
330: + i)
331: + ";");
332: } else {
333: // Arg. constructor jpa/0u21
334: if (i != 0)
335: out.print(", ");
336:
337: out.print(" a" + i);
338:
339: if (i + 1 == keys.size())
340: out.println(");");
341: }
342: }
343: }
344:
345: out.println("return key;");
346:
347: out.popDepth();
348: out.println("}");
349: }
350:
351: /**
352: * Returns the foreign type.
353: */
354: public int generateLoadForeign(JavaWriter out, String rs,
355: String indexVar, int index) throws IOException {
356: return generateLoadForeign(out, rs, indexVar, index,
357: getForeignTypeName().replace('.', '_'));
358: }
359:
360: /**
361: * Returns the foreign type.
362: */
363: public int generateLoadForeign(JavaWriter out, String rs,
364: String indexVar, int index, String name) throws IOException {
365: out.print("__caucho_load_key_" + getForeignMakeKeyName());
366: out.print("(aConn, " + rs + ", " + indexVar + " + " + index
367: + ")");
368:
369: ArrayList<IdField> keys = getKeys();
370:
371: index += keys.size();
372:
373: return index;
374: }
375:
376: /**
377: * Generates the select clause.
378: */
379: public String generateSelect(String id) {
380: ArrayList<IdField> keys = getKeys();
381:
382: CharBuffer cb = CharBuffer.allocate();
383:
384: for (int i = 0; i < keys.size(); i++) {
385: if (i != 0)
386: cb.append(", ");
387:
388: cb.append(keys.get(i).generateSelect(id));
389: }
390:
391: return cb.close();
392: }
393:
394: /**
395: * Generates the JPA QL select clause.
396: */
397: public String generateJavaSelect(String id) {
398: ArrayList<IdField> keys = getKeys();
399:
400: CharBuffer cb = CharBuffer.allocate();
401:
402: for (int i = 0; i < keys.size(); i++) {
403: if (i != 0)
404: cb.append(", ");
405:
406: cb.append(keys.get(i).generateJavaSelect(id));
407: }
408:
409: return cb.close();
410: }
411:
412: /**
413: * Generates the select clause.
414: */
415: public String generateLoadSelect(String id) {
416: return null;
417: }
418:
419: /**
420: * Returns the key for the value
421: */
422: public String generateGetProperty(String value) {
423: CharBuffer cb = CharBuffer.allocate();
424:
425: cb.append("__caucho_make_key_" + getForeignMakeKeyName());
426: cb.append("(");
427:
428: ArrayList<IdField> keys = getKeys();
429:
430: for (int i = 0; i < keys.size(); i++) {
431: if (i != 0)
432: cb.append(", ");
433:
434: cb.append(keys.get(i).generateGet(value));
435: }
436:
437: cb.append(")");
438:
439: return cb.close();
440: }
441:
442: /**
443: * Returns the key for the value
444: */
445: public String generateGetProxyProperty(String value) {
446: CharBuffer cb = CharBuffer.allocate();
447:
448: cb.append("__caucho_make_key_" + getForeignMakeKeyName());
449: cb.append("(");
450:
451: ArrayList<IdField> keys = getKeys();
452:
453: for (int i = 0; i < keys.size(); i++) {
454: if (i != 0)
455: cb.append(", ");
456:
457: cb.append(keys.get(i).generateGetProxyProperty(value));
458: }
459:
460: cb.append(")");
461:
462: return cb.close();
463: }
464:
465: /**
466: * Generates loading cache
467: */
468: public void generateLoadFromObject(JavaWriter out, String obj)
469: throws IOException {
470: ArrayList<IdField> keys = getKeys();
471:
472: for (int i = 0; i < keys.size(); i++) {
473: keys.get(i).generateLoadFromObject(out, obj);
474: }
475: }
476:
477: /**
478: * Generates loading cache
479: */
480: public void generateSet(JavaWriter out, String obj)
481: throws IOException {
482: out.println("if (" + obj + " != null) {");
483: out.pushDepth();
484:
485: AmberPersistenceUnit persistenceUnit = getOwnerType()
486: .getPersistenceUnit();
487:
488: // ejb/06ie
489: if (persistenceUnit.isJPA() && !isEmbeddedId()) {
490:
491: // jpa/0u21
492:
493: EmbeddableType embeddable = persistenceUnit
494: .getEmbeddable(_keyClass.getName());
495:
496: // jpa/0u21 ArrayList<IdField> keys = getKeys();
497: ArrayList<AmberField> keys = embeddable.getFields();
498:
499: for (int i = 0; i < keys.size(); i++) {
500: PropertyField key = (PropertyField) keys.get(i);
501:
502: String getter = "__caucho_get_field(" + i + ")";
503:
504: String value = "((com.caucho.amber.entity.Embeddable) key)."
505: + getter;
506:
507: out.println("Object field" + i + " = " + value + ";");
508:
509: out.println("if (field" + i + " == null)");
510: out.println(" return;");
511:
512: KeyPropertyField prop = null;
513:
514: Column column = key.getColumn();
515:
516: // jpa/0j55
517: if (true || column == null) {
518: ArrayList<IdField> fields = getKeys();
519: for (int j = 0; j < fields.size(); j++) {
520: IdField id = fields.get(j);
521: if (id.getName().equals(key.getName()))
522: if (id instanceof KeyPropertyField)
523: prop = (KeyPropertyField) id;
524: }
525: }
526:
527: if (prop != null)
528: key = prop;
529:
530: Type columnType = key.getColumn().getType();
531:
532: value = columnType.generateCastFromObject("field" + i);
533:
534: key.generateSet(out, value);
535: }
536:
537: // jpa/0u21
538: out.println("__caucho_compound_key = ("
539: + getForeignTypeName() + ") " + obj + ";");
540:
541: /*
542: for (int i = 0; i < keys.size(); i++) {
543: IdField key = keys.get(i);
544:
545: key.generateSet(out, key.generateGetKeyProperty(obj + "_key"));
546: }
547: */
548: } else {
549: out.println(getForeignTypeName() + " " + obj + "_key = ("
550: + getForeignTypeName() + ") " + obj + ";");
551:
552: if (getEmbeddedIdField() == null) {
553: // ejb/06ie
554:
555: ArrayList<IdField> keys = getKeys();
556:
557: for (int i = 0; i < keys.size(); i++) {
558: IdField key = keys.get(i);
559:
560: key.generateSet(out, key.generateGetKeyProperty(obj
561: + "_key"));
562: }
563: } else
564: getEmbeddedIdField().generateSet(out, obj + "_key");
565: }
566:
567: out.popDepth();
568: out.println("}");
569: }
570:
571: /**
572: * Generates loading cache
573: */
574: public void generateUpdateFromObject(JavaWriter out, String obj)
575: throws IOException {
576: ArrayList<IdField> keys = getKeys();
577:
578: for (int i = 0; i < keys.size(); i++) {
579: keys.get(i).generateUpdateFromObject(out, obj);
580: }
581: }
582:
583: /**
584: * Generates the where clause.
585: */
586: public String generateWhere(String id) {
587: ArrayList<IdField> keys = getKeys();
588:
589: CharBuffer cb = CharBuffer.allocate();
590:
591: for (int i = 0; i < keys.size(); i++) {
592: if (i != 0)
593: cb.append(" and ");
594:
595: cb.append(keys.get(i).generateWhere(id));
596: }
597:
598: return cb.close();
599: }
600:
601: /**
602: * Generates the where clause.
603: */
604: public String generateCreateTableSQL(AmberPersistenceUnit manager) {
605: return null;
606: }
607:
608: /**
609: * Generates the set clause.
610: */
611: public void generateSetKey(JavaWriter out, String pstmt,
612: String obj, String index) throws IOException {
613: generateSet(out, pstmt, obj, index);
614: }
615:
616: /**
617: * Generates code to convert to the type from the object.
618: */
619: public String generateCastFromObject(String value) {
620: return value;
621: }
622:
623: /**
624: * Generates code for a match.
625: */
626: public void generateMatch(JavaWriter out, String key)
627: throws IOException {
628: out.println("return __caucho_getPrimaryKey().equals(" + key
629: + ");");
630: }
631:
632: /**
633: * Generates code to test the equals.
634: */
635: public String generateEquals(String leftBase, String value) {
636: return leftBase + ".equals(" + value + ")";
637: }
638:
639: /**
640: * Generates the set clause.
641: */
642: public void generateCheckCreateKey(JavaWriter out)
643: throws IOException {
644: }
645:
646: /**
647: * Generates the set clause.
648: */
649: /*
650: public void generateSetGeneratedKeys(JavaWriter out, String pstmt)
651: throws IOException
652: {
653: }
654: */
655:
656: /**
657: * Generates code to convert to the object.
658: */
659: public String toObject(String value) {
660: return value;
661: }
662: }
|