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.expr.AmberExpr;
033: import com.caucho.amber.expr.PathExpr;
034: import com.caucho.amber.manager.AmberConnection;
035: import com.caucho.amber.manager.AmberPersistenceUnit;
036: import com.caucho.amber.query.QueryParser;
037: import com.caucho.amber.table.Table;
038: import com.caucho.amber.table.Column;
039: import com.caucho.amber.type.AbstractStatefulType;
040: import com.caucho.amber.type.RelatedType;
041: import com.caucho.bytecode.JClass;
042: import com.caucho.bytecode.JClassWrapper;
043: import com.caucho.bytecode.JField;
044: import com.caucho.bytecode.JMethod;
045: import com.caucho.bytecode.JType;
046: import com.caucho.config.ConfigException;
047: import com.caucho.java.JavaWriter;
048: import com.caucho.log.Log;
049: import com.caucho.util.CharBuffer;
050: import com.caucho.util.L10N;
051:
052: import java.io.IOException;
053: import java.io.Serializable;
054: import java.sql.SQLException;
055: import java.util.ArrayList;
056: import java.util.HashSet;
057: import java.util.logging.Level;
058: import java.util.logging.Logger;
059:
060: /**
061: * Configuration for a bean's property
062: */
063: abstract public class AbstractField implements AmberField {
064: private static final L10N L = new L10N(AbstractField.class);
065: protected static final Logger log = Log.open(AbstractField.class);
066:
067: AbstractStatefulType _sourceType;
068:
069: private String _name;
070:
071: private JType _javaType;
072:
073: private JMethod _getterMethod;
074: private JMethod _setterMethod;
075:
076: private boolean _isLazy = true;
077:
078: private int _updateIndex;
079: private int _loadGroupIndex = -1;
080:
081: AbstractField(AbstractStatefulType sourceType) {
082: _sourceType = sourceType;
083: }
084:
085: AbstractField(AbstractStatefulType sourceType, String name)
086: throws ConfigException {
087: this (sourceType);
088:
089: if (log.isLoggable(Level.FINER)) {
090: log.log(Level.FINER, sourceType + " "
091: + getClass().getSimpleName() + "[" + name + "]");
092: }
093:
094: setName(name);
095: }
096:
097: /**
098: * Sets the name.
099: */
100: public void setName(String name) throws ConfigException {
101: _name = name;
102:
103: if (!isFieldAccess()) {
104: char ch = name.charAt(0);
105: if (Character.isLowerCase(ch))
106: name = Character.toUpperCase(ch) + name.substring(1);
107:
108: String getter = "get" + name;
109: String setter = "set" + name;
110:
111: _getterMethod = AbstractStatefulType.getGetter(
112: getBeanClass(), getter);
113:
114: if (_getterMethod == null) {
115: getter = "is" + name;
116: _getterMethod = AbstractStatefulType.getGetter(
117: getBeanClass(), getter);
118: }
119:
120: /* jpa/0u21
121: if (_getterMethod == null)
122: throw new ConfigException(L.l("{0}: {1} has no matching getter.",
123: getBeanClass().getName(), name));
124: */
125:
126: if (_getterMethod == null) {
127: JField field = AbstractStatefulType.getField(
128: getBeanClass(), _name);
129:
130: if (field == null)
131: throw new ConfigException(L.l(
132: "{0}: {1} has no matching field.",
133: getBeanClass().getName(), _name));
134:
135: _javaType = field.getGenericType();
136: } else {
137: _javaType = _getterMethod.getGenericReturnType();
138:
139: _setterMethod = AbstractStatefulType.getSetter(
140: getBeanClass(), setter);
141: }
142: } else {
143: JField field = AbstractStatefulType.getField(
144: getBeanClass(), name);
145:
146: if (field == null)
147: throw new ConfigException(L.l(
148: "{0}: {1} has no matching field.",
149: getBeanClass().getName(), name));
150:
151: _javaType = field.getGenericType();
152: }
153:
154: /*
155: if (_setterMethod == null && ! isAbstract())
156: throw new ConfigException(L.l("{0}: {1} has no matching setter.",
157: getBeanClass().getName(), name));
158: */
159: }
160:
161: /**
162: * Returns the field name.
163: */
164: public String getName() {
165: return _name;
166: }
167:
168: /**
169: * Sets the java type.
170: */
171: protected void setJavaType(JType type) {
172: _javaType = type;
173: }
174:
175: /**
176: * Sets the java type.
177: */
178: protected void setJavaType(Class type) {
179: setJavaType(new JClassWrapper(type, getPersistenceUnit()
180: .getJClassLoader()));
181: }
182:
183: /**
184: * Returns the owning entity class.
185: */
186: public AbstractStatefulType getSourceType() {
187: return _sourceType;
188: }
189:
190: /**
191: * Returns the amber manager.
192: */
193: public AmberPersistenceUnit getPersistenceUnit() {
194: return getSourceType().getPersistenceUnit();
195: }
196:
197: /**
198: * Returns the bean class.
199: */
200: public JClass getBeanClass() {
201: return getSourceType().getBeanClass();
202: }
203:
204: /**
205: * Returns the source type as
206: * entity or mapped-superclass.
207: */
208: public RelatedType getEntitySourceType() {
209: return (RelatedType) getSourceType();
210: }
211:
212: /**
213: * Returns the table containing the field's columns.
214: */
215: public Table getTable() {
216: return getEntitySourceType().getTable();
217: }
218:
219: /**
220: * Returns the column for the field
221: */
222: public Column getColumn() {
223: return null;
224: }
225:
226: /**
227: * Returns the property index.
228: */
229: public int getIndex() {
230: return _updateIndex;
231: }
232:
233: /**
234: * Set the property index.
235: */
236: public void setIndex(int index) {
237: _updateIndex = index;
238: }
239:
240: /**
241: * Returns the property's group index.
242: */
243: public int getLoadGroupIndex() {
244: return _loadGroupIndex;
245: }
246:
247: /**
248: * Returns the property's group index.
249: */
250: protected void setLoadGroupIndex(int index) {
251: _loadGroupIndex = index;
252: }
253:
254: /**
255: * Returns the load group mask.
256: */
257: public long getCreateLoadMask(int group) {
258: int index = getLoadGroupIndex();
259:
260: if (64 * group <= index && index < 64 * (group + 1))
261: return 1L << (index % 64);
262: else
263: return 0;
264: }
265:
266: /**
267: * Returns true for a lazy field.
268: */
269: public boolean isLazy() {
270: return _isLazy;
271: }
272:
273: /**
274: * Set true for a lazy field.
275: */
276: public void setLazy(boolean isLazy) {
277: _isLazy = isLazy;
278: }
279:
280: /**
281: * Returns the getter method.
282: */
283: public JMethod getGetterMethod() {
284: return _getterMethod;
285: }
286:
287: /**
288: * Returns the getter name.
289: */
290: public String getGetterName() {
291: if (isFieldAccess())
292: return "__caucho_get_" + getName();
293: else
294: return _getterMethod.getName();
295: }
296:
297: /**
298: * Returns the getter name.
299: */
300: public String getJavaTypeName() {
301: return getJavaType().getPrintName();
302: }
303:
304: /**
305: * Returns the Java code for the type.
306: */
307: private String getJavaTypeName(Class cl) {
308: if (cl.isArray())
309: return getJavaTypeName(cl.getComponentType()) + "[]";
310: else
311: return cl.getName();
312: }
313:
314: /**
315: * Returns the field's type
316: */
317: public JType getJavaType() {
318: return _javaType;
319: }
320:
321: /**
322: * Returns the setter method.
323: */
324: public JMethod getSetterMethod() {
325: return _setterMethod;
326: }
327:
328: /**
329: * Returns the setter name.
330: */
331: public String getSetterName() {
332: if (isFieldAccess())
333: return "__caucho_set_" + getName();
334: else if (_setterMethod != null)
335: return _setterMethod.getName();
336: else
337: return "set" + getGetterName().substring(3);
338: }
339:
340: /**
341: * Returns true if values are accessed by the fields.
342: */
343: public boolean isFieldAccess() {
344: return getSourceType().isFieldAccess();
345: }
346:
347: /**
348: * Returns true if the methods are abstract.
349: */
350: public boolean isAbstract() {
351: // jpa/0u21
352:
353: if (isFieldAccess() || getSourceType().isIdClass())
354: return true;
355: else if (_getterMethod == null)
356: return false;
357: else
358: return _getterMethod.isAbstract();
359: }
360:
361: /**
362: * Returns true if the field is cascadable.
363: */
364: public boolean isCascadable() {
365: return false;
366: }
367:
368: /**
369: * Returns true if the methods are abstract.
370: */
371: public boolean isUpdateable() {
372: return true;
373: }
374:
375: /**
376: * Initialize the field.
377: */
378: public void init() throws ConfigException {
379: if (_loadGroupIndex < 0) {
380: if (_isLazy)
381: _loadGroupIndex = getEntitySourceType()
382: .nextLoadGroupIndex();
383: else
384: _loadGroupIndex = getEntitySourceType()
385: .getDefaultLoadGroupIndex();
386: }
387: }
388:
389: /**
390: * Generates the post constructor initialization.
391: */
392: public void generatePostConstructor(JavaWriter out)
393: throws IOException {
394: }
395:
396: /**
397: * Generates any prologue.
398: */
399: public void generatePrologue(JavaWriter out,
400: HashSet<Object> completedSet) throws IOException {
401: if (isAbstract()) {
402: out.println();
403: out.print("public ");
404: out.print(getJavaType().getPrintName());
405: out.print(" " + getFieldName() + ";");
406: }
407: }
408:
409: /**
410: * Generates the select clause for an entity load.
411: */
412: public String generateLoadSelect(Table table, String id) {
413: return null;
414: }
415:
416: /**
417: * Generates the select clause.
418: */
419: public String generateSelect(String id) {
420: return null;
421: }
422:
423: /**
424: * Generates the JPA QL select clause.
425: */
426: public String generateJavaSelect(String id) {
427: return null;
428: }
429:
430: /**
431: * Generates the where clause.
432: */
433: public String generateWhere(String id) {
434: return null;
435: }
436:
437: /**
438: * Generates the where clause.
439: */
440: public void generateUpdate(CharBuffer sql) {
441: }
442:
443: /**
444: * Generates loading cache
445: */
446: public void generateUpdate(JavaWriter out, String maskVar,
447: String pstmt, String index) throws IOException {
448: int group = getIndex() / 64;
449: long mask = 1L << getIndex() % 64;
450:
451: out.println();
452: out.println("if ((" + maskVar + "_" + group + " & " + mask
453: + "L) != 0) {");
454: out.pushDepth();
455:
456: generateSet(out, pstmt, index);
457:
458: out.popDepth();
459: out.println("}");
460: }
461:
462: /**
463: * Generates loading code
464: */
465: public boolean hasLoadGroup(int index) {
466: return index == _loadGroupIndex;
467: }
468:
469: /**
470: * Generates loading code
471: */
472: public int generateLoad(JavaWriter out, String rs, String indexVar,
473: int index) throws IOException {
474: return index;
475: }
476:
477: /**
478: * Generates loading code after the basic fields.
479: */
480: public int generatePostLoadSelect(JavaWriter out, int index)
481: throws IOException {
482: return index;
483: }
484:
485: /**
486: * Generates loading cache
487: */
488: public void generateLoadFromObject(JavaWriter out, String obj)
489: throws IOException {
490: if (getGetterMethod() == null || getSetterMethod() == null)
491: return;
492:
493: String getter = getGetterName();
494:
495: String loadVar = "__caucho_loadMask_"
496: + (getLoadGroupIndex() / 64);
497: long loadMask = (1L << getLoadGroupIndex());
498:
499: out.println("if ((" + loadVar + " & " + loadMask + "L) != 0)");
500: out.print(" ");
501:
502: out.println(" " + generateSuperSetter(generateGet(obj)) + ";");
503: }
504:
505: /**
506: * Generates loading cache
507: */
508: public void generateSet(JavaWriter out, String obj)
509: throws IOException {
510: out.println(generateSuperSetter(obj) + ";");
511: }
512:
513: /**
514: * Generates loading cache
515: */
516: public void generateUpdateFromObject(JavaWriter out, String obj)
517: throws IOException {
518: out.println(generateSuperSetter(generateGet(obj)) + ";");
519: }
520:
521: /**
522: * Generates the field getter.
523: *
524: * @param value the non-null value
525: */
526: public void generateGet(JavaWriter out, String value)
527: throws IOException {
528: out.print(generateGet(value));
529: }
530:
531: /**
532: * Returns the null value.
533: */
534: public String generateNull() {
535: return "null";
536: }
537:
538: /**
539: * Generates the field getter.
540: *
541: * @param value the non-null value
542: */
543: public String generateGet(String obj) {
544: if (obj == null)
545: return generateNull();
546:
547: if (obj.equals("super"))
548: return generateSuperGetter();
549: else if (!isAbstract())
550: return obj + "." + _getterMethod.getName() + "()";
551: else if (_getterMethod != null)
552: return obj + "." + _getterMethod.getName() + "()";
553: else
554: return obj + "." + getFieldName();
555: }
556:
557: /**
558: * Generates the field setter.
559: *
560: * @param value the non-null value
561: */
562: public String generateSet(String obj, String value) {
563: if (obj.equals("super"))
564: return generateSuperSetter(value);
565: else if (isAbstract()) {
566: if (isFieldAccess()) {
567: // jpa/0h09
568: return obj + "." + getSetterName() + "(" + value + ")";
569: }
570:
571: return obj + "." + getFieldName() + " = " + value;
572: } else if (_setterMethod != null)
573: return obj + "." + _setterMethod.getName() + "(" + value
574: + ")";
575: else
576: return ""; // ejb/0gb9
577: }
578:
579: /**
580: * Returns the field name.
581: */
582: protected String getFieldName() {
583: return "__amber_" + getName();
584: }
585:
586: /**
587: * Generates the insert.
588: */
589: public final String generateInsert() {
590: return null;
591: }
592:
593: /**
594: * Generates the insert.
595: */
596: public void generateInsertColumns(ArrayList<String> columns) {
597: }
598:
599: /**
600: * Generates the get property.
601: */
602: public void generateGetProperty(JavaWriter out) throws IOException {
603:
604: }
605:
606: /**
607: * Generates the set property.
608: */
609: public void generateSetProperty(JavaWriter out) throws IOException {
610: }
611:
612: /**
613: * Returns the actual data.
614: */
615: public String generateSuperGetter() {
616: if (!getSourceType().isEmbeddable())
617: return "__caucho_super_get_" + getName() + "()";
618: else if (isFieldAccess())
619: return getName();
620: else
621: return getGetterMethod().getName() + "()";
622: }
623:
624: /**
625: * Sets the actual data.
626: */
627: public final String generateSuperSetter(String value) {
628: return generateSuperSetter("this", value);
629: }
630:
631: /**
632: * Sets the actual data.
633: */
634: public String generateSuperSetter(String objThis, String value) {
635: if (!getSourceType().isEmbeddable())
636: return objThis + "." + "__caucho_super_set_" + getName()
637: + "(" + value + ")";
638: else if (isFieldAccess()) {
639: return objThis + "." + getName() + " = " + value;
640: } else {
641: return objThis + "." + getSetterMethod().getName() + "("
642: + value + ")";
643: }
644: }
645:
646: /**
647: * Generates the get property.
648: */
649: public void generateSuperGetter(JavaWriter out) throws IOException {
650: out.println();
651: out.println("public final " + getJavaTypeName()
652: + " __caucho_super_get_" + getName() + "()");
653: out.println("{");
654: out.pushDepth();
655:
656: if (isAbstract() || getGetterMethod() == null)
657: out.println("return " + getFieldName() + ";");
658: else
659: out.println("return super." + getGetterName() + "();");
660:
661: out.popDepth();
662: out.println("}");
663: }
664:
665: /**
666: * Generates the set property.
667: */
668: public void generateSuperSetter(JavaWriter out) throws IOException {
669: out.println();
670: out.println("public final void __caucho_super_set_" + getName()
671: + "(" + getJavaTypeName() + " v)");
672: out.println("{");
673: out.pushDepth();
674:
675: if (isAbstract() || getGetterMethod() == null)
676: out.println(getFieldName() + " = v;");
677: else if (getSetterMethod() != null)
678: out
679: .println("super." + getSetterMethod().getName()
680: + "(v);");
681:
682: out.popDepth();
683: out.println("}");
684: }
685:
686: /**
687: * Generates the table create.
688: */
689: public String generateCreateTableSQL(AmberPersistenceUnit manager) {
690: return null;
691: }
692:
693: /**
694: * Generates the set clause.
695: */
696: public void generateSet(JavaWriter out, String pstmt, String index)
697: throws IOException {
698: generateSet(out, pstmt, index, "super");
699: }
700:
701: /**
702: * Generates the set clause for the insert clause.
703: */
704: public void generateInsertSet(JavaWriter out, String pstmt,
705: String index, String obj) throws IOException {
706: generateSet(out, pstmt, index, obj);
707: }
708:
709: /**
710: * Generates the set clause for the insert clause.
711: */
712: public void generateUpdateSet(JavaWriter out, String pstmt,
713: String index, String obj) throws IOException {
714: generateSet(out, pstmt, index, obj);
715: }
716:
717: /**
718: * Updates the cached copy.
719: */
720: public void generateCopyUpdateObject(JavaWriter out, String dst,
721: String src, int updateIndex) throws IOException {
722: // commented out: jpa/0l03
723:
724: if (getIndex() == updateIndex) {
725: String value = generateGet(src);
726: out.println(generateSet(dst, value) + ";");
727: }
728: }
729:
730: /**
731: * Updates the cached copy.
732: */
733: public void generateCopyLoadObject(JavaWriter out, String dst,
734: String src, int loadIndex) throws IOException {
735: // jpa/0g0l
736: if (getLoadGroupIndex() != loadIndex)
737: return;
738:
739: String value = generateGet(src);
740:
741: // jpa/0l43 out.println(generateSet(dst, value) + ";");
742:
743: boolean isJPA = getEntitySourceType().getPersistenceUnit()
744: .isJPA();
745:
746: if (isJPA
747: && !(dst.equals("cacheEntity") || dst.equals("super") || dst
748: .equals("item"))) {
749: // jpa/0j5fn: merge()
750: out.println("if (isFullMerge)");
751: out.println(" " + generateSet(dst, value) + ";");
752: out.println("else");
753: out.print(" ");
754: }
755:
756: if (!dst.equals("super"))
757: out.println(generateSuperSetter(dst, value) + ";");
758: else
759: out.println(generateSuperSetter("this", value) + ";");
760: }
761:
762: /**
763: * Updates the cached copy.
764: */
765: public void generateCopyMergeObject(JavaWriter out, String dst,
766: String src, int loadIndex) throws IOException {
767: }
768:
769: /**
770: * Checks entity-relationships from an object.
771: */
772: public void generateDumpRelationships(JavaWriter out,
773: int updateIndex) throws IOException {
774: }
775:
776: /**
777: * Generates the set clause.
778: */
779: public void generateSet(JavaWriter out, String pstmt, String index,
780: String obj) throws IOException {
781: }
782:
783: /**
784: * Converts to an object.
785: */
786: public String toObject(String value) {
787: return value;
788: }
789:
790: /**
791: * Links to the target.
792: */
793: public void link() {
794: }
795:
796: /**
797: * Generates the pre-delete code
798: */
799: public void generatePreDelete(JavaWriter out) throws IOException {
800: }
801:
802: /**
803: * Generates the delete foreign
804: */
805: public void generatePostDelete(JavaWriter out) throws IOException {
806: }
807:
808: /**
809: * Generates the expire code
810: */
811: public void generateExpire(JavaWriter out) throws IOException {
812: }
813:
814: /**
815: * Generates code for foreign entity create/delete
816: */
817: public void generateInvalidateForeign(JavaWriter out)
818: throws IOException {
819: }
820:
821: /**
822: * Deletes the children
823: */
824: public void childDelete(AmberConnection aConn,
825: Serializable primaryKey) throws SQLException {
826: }
827:
828: /**
829: * Generates code to convert to the type from the object.
830: */
831: public String generateCastFromObject(String value) {
832: return value;
833: }
834:
835: /**
836: * Generates code to test the equals.
837: */
838: public String generateEquals(String leftBase, String value) {
839: return leftBase + ".equals(" + value + ")";
840: }
841:
842: /**
843: * Creates the expression for the field.
844: */
845: public AmberExpr createExpr(QueryParser parser, PathExpr parent) {
846: throw new UnsupportedOperationException(getClass().getName());
847: }
848:
849: public String toString() {
850: return getClass().getSimpleName() + "[" + getName() + ","
851: + getSourceType() + "]";
852: }
853: }
|