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.cfg.AbstractConfigIntrospector;
033: import com.caucho.amber.expr.AmberExpr;
034: import com.caucho.amber.expr.ColumnExpr;
035: import com.caucho.amber.expr.EmbeddedExpr;
036: import com.caucho.amber.expr.PathExpr;
037: import com.caucho.amber.query.QueryParser;
038: import com.caucho.amber.table.Column;
039: import com.caucho.amber.table.ForeignColumn;
040: import com.caucho.amber.table.Table;
041: import com.caucho.amber.type.*;
042: import com.caucho.config.ConfigException;
043: import com.caucho.java.JavaWriter;
044: import com.caucho.log.Log;
045: import com.caucho.util.CharBuffer;
046: import com.caucho.util.L10N;
047:
048: import java.io.IOException;
049: import java.util.ArrayList;
050: import java.util.logging.Logger;
051:
052: /**
053: * Configuration for a bean's field
054: */
055: public class PropertyField extends AbstractField {
056: private static final L10N L = new L10N(PropertyField.class);
057: protected static final Logger log = Log.open(PropertyField.class);
058:
059: private Column _column;
060: private Type _type;
061:
062: private KeyManyToOneField _aliasKey;
063:
064: private boolean _isInsert = true;
065: private boolean _isUpdate = true;
066:
067: public PropertyField(AbstractStatefulType statefulType, String name)
068: throws ConfigException {
069: super (statefulType, name);
070: }
071:
072: public PropertyField(AbstractStatefulType statefulType) {
073: super (statefulType);
074: }
075:
076: /**
077: * Sets the result type.
078: */
079: public void setType(Type type) {
080: _type = type;
081: }
082:
083: /**
084: * Sets the result type.
085: */
086: public Type getType() {
087: return _type;
088: }
089:
090: /**
091: * Returns the source type as
092: * entity or mapped-superclass.
093: */
094: public RelatedType getRelatedSourceType() {
095: return (RelatedType) getSourceType();
096: }
097:
098: /**
099: * Returns the table containing the field's columns.
100: */
101: public Table getTable() {
102: return getColumn().getTable();
103: }
104:
105: /**
106: * Sets the column.
107: */
108: public void setColumn(Column column) {
109: _column = column;
110: }
111:
112: /**
113: * Gets the column.
114: */
115: public Column getColumn() {
116: return _column;
117: }
118:
119: /**
120: * Set true if the property should be saved on an insert.
121: */
122: public void setInsert(boolean isInsert) {
123: _isInsert = isInsert;
124: }
125:
126: /**
127: * Set true if the property should be saved on an update.
128: */
129: public void setUpdate(boolean isUpdate) {
130: _isUpdate = isUpdate;
131: }
132:
133: /**
134: * Initializes the property.
135: */
136: public void init() throws ConfigException {
137: super .init();
138:
139: if (getColumn() == null)
140: throw new IllegalStateException(L
141: .l("column must be set before init"));
142:
143: // Embedded types have no id.
144: // Only entity or mapped-superclass types have id.
145: if (!(getSourceType() instanceof RelatedType))
146: return;
147:
148: if (getRelatedSourceType().getId() != null) {
149: // resolve any alias
150: for (AmberField field : getRelatedSourceType().getId()
151: .getKeys()) {
152: if (field instanceof KeyManyToOneField) {
153: KeyManyToOneField key = (KeyManyToOneField) field;
154:
155: for (ForeignColumn column : key.getLinkColumns()
156: .getColumns()) {
157: if (getColumn().getName().equals(
158: column.getName()))
159: _aliasKey = key;
160: }
161: }
162: }
163: }
164: }
165:
166: /**
167: * Returns the null value.
168: */
169: public String generateNull() {
170: return getType().generateNull();
171: }
172:
173: /**
174: * Returns the field name.
175: */
176: protected String getFieldName() {
177: // jpa/0w01, jpa/0w10
178: if (getColumn() == null)
179: return "__amber_"
180: + AbstractConfigIntrospector.toSqlName(getName());
181:
182: return getColumn().getFieldName();
183: }
184:
185: /**
186: * Generates the set property.
187: */
188: public void generateGetProperty(JavaWriter out) throws IOException {
189: if (!isFieldAccess() && getGetterMethod() == null)
190: return;
191:
192: out.println();
193: out.println("public " + getJavaTypeName() + " "
194: + getGetterName() + "()");
195: out.println("{");
196: out.pushDepth();
197:
198: if (!(getSourceType() instanceof EmbeddableType)) {
199: out.println("if (__caucho_session != null)");
200: out.println(" __caucho_load_select_" + getLoadGroupIndex()
201: + "(__caucho_session);");
202: out.println();
203: }
204:
205: out.println("return " + generateSuperGetter() + ";");
206:
207: out.popDepth();
208: out.println("}");
209: }
210:
211: /**
212: * Generates the set property.
213: */
214: public void generateSetProperty(JavaWriter out) throws IOException {
215: if (!isFieldAccess()
216: && (getGetterMethod() == null || getSetterMethod() == null
217: && !isAbstract()))
218: return;
219:
220: out.println();
221: out.println("public void " + getSetterName() + "("
222: + getJavaTypeName() + " v)");
223: out.println("{");
224: out.pushDepth();
225:
226: int maskGroup = getLoadGroupIndex() / 64;
227: String loadVar = "__caucho_loadMask_" + maskGroup;
228:
229: long mask = 1L << (getLoadGroupIndex() % 64);
230:
231: // jpa/0gh0
232: if (getSourceType() instanceof EmbeddableType) {
233: out.println(generateSuperSetter("v") + ";");
234: out.popDepth();
235: out.println("}");
236: return;
237: } else {
238: // jpa/0g06, jpa/0g0k, jpa/0j5f
239: out.println("if ((" + loadVar + " & " + mask
240: + "L) == 0 && __caucho_session != null) {");
241: out.println(" __caucho_load_" + maskGroup
242: + "(__caucho_session);");
243: out.println();
244: out
245: .println(" if (__caucho_session.isActiveTransaction())");
246: out
247: .println(" __caucho_session.makeTransactional((com.caucho.amber.entity.Entity) this);");
248: out.println("}");
249: out.println();
250: }
251:
252: if (!_isUpdate) {
253: out.println("if (__caucho_session == null)");
254: out.println(" " + generateSuperSetter("v") + ";");
255: } else {
256: out.println(getJavaTypeName() + " oldValue = "
257: + generateSuperGetter() + ";");
258:
259: if (getJavaTypeName().equals("java.lang.String")) {
260: out
261: .println("if ((oldValue == v || v != null && v.equals(oldValue)) && ("
262: + loadVar + " & " + mask + "L) != 0L)");
263: out.println(" return;");
264: } else {
265: out.println("if (oldValue == v && (" + loadVar + " & "
266: + mask + "L) != 0)");
267: out.println(" return;");
268: }
269:
270: out.println("try {");
271: out.pushDepth();
272:
273: out.println(generateSuperSetter("v") + ";");
274:
275: out.popDepth();
276: out.println("} catch (Exception e1) {");
277: out.pushDepth();
278:
279: out.println("if (__caucho_session != null) {");
280: out.pushDepth();
281: out.println("try {");
282: out.println(" __caucho_session.rollback();");
283: out.println("} catch (java.sql.SQLException e2) {");
284: out
285: .println(" throw new javax.persistence.PersistenceException(e2);");
286: out.println("}");
287: out.println();
288: out
289: .println("throw new javax.persistence.PersistenceException(e1);");
290: out.popDepth();
291: out.println("}");
292:
293: out.popDepth();
294: out.println("}");
295:
296: int dirtyGroup = getIndex() / 64;
297: String dirtyVar = "__caucho_dirtyMask_" + dirtyGroup;
298:
299: long dirtyMask = 1L << (getIndex() % 64);
300:
301: out.println();
302: out.println("long oldMask = " + dirtyVar + ";");
303: out.println(dirtyVar + " |= " + dirtyMask + "L;");
304:
305: out.println();
306: out
307: .println("if (__caucho_session != null && oldMask == 0)");
308: out
309: .println(" __caucho_session.update((com.caucho.amber.entity.Entity) this);");
310: out.println();
311: out.println("__caucho_increment_version();");
312: }
313:
314: out.popDepth();
315: out.println("}");
316: }
317:
318: /**
319: * Generates the select clause.
320: */
321: public String generateLoadSelect(Table table, String id) {
322: if (getColumn().getTable() != table) {
323: // jpa/0l14 as a negative test
324: if (getRelatedSourceType() instanceof EntityType)
325: return null;
326: }
327:
328: return generateSelect(id);
329: }
330:
331: /**
332: * Generates the select clause.
333: */
334: public String generateSelect(String id) {
335: return getColumn().generateSelect(id);
336: }
337:
338: /**
339: * Generates the where clause.
340: */
341: public String generateWhere(String id) {
342: return getColumn().generateSelect(id);
343: }
344:
345: /**
346: * Generates the insert.
347: */
348: public void generateInsertColumns(ArrayList<String> columns) {
349: if (_isInsert && _aliasKey == null)
350: columns.add(getColumn().getName());
351: }
352:
353: /**
354: * Generates the update set clause
355: */
356: public void generateUpdate(CharBuffer sql) {
357: if (_isUpdate && _aliasKey == null)
358: sql.append(getColumn().generateUpdateSet());
359: /*
360: sql.append(getColumn());
361: sql.append("=?");
362: */
363: }
364:
365: /**
366: * Generates the set clause for the insert clause.
367: */
368: public void generateInsertSet(JavaWriter out, String pstmt,
369: String index, String obj) throws IOException {
370: if (_aliasKey != null) {
371: } else if (_isInsert)
372: generateSet(out, pstmt, index, obj);
373: else if (getLoadGroupIndex() != 0) {
374: int groupIndex = getLoadGroupIndex();
375: int group = groupIndex / 64;
376: long groupMask = 1L << (groupIndex % 64);
377: out.println("__caucho_loadMask_" + group + " &= ~"
378: + groupMask + "L;");
379: }
380: }
381:
382: /**
383: * Generates the set clause for the insert clause.
384: */
385: public void generateUpdateSet(JavaWriter out, String pstmt,
386: String index, String obj) throws IOException {
387: if (_isUpdate && _aliasKey == null)
388: generateSet(out, pstmt, index, obj);
389: }
390:
391: /**
392: * Generates the set clause.
393: */
394: public void generateSet(JavaWriter out, String pstmt, String index,
395: String obj) throws IOException {
396: // XXX: need to find QA explaining the following test
397: if (!isFieldAccess() && getGetterMethod() == null
398: || _aliasKey != null)
399: return;
400:
401: getColumn().generateSet(out, pstmt, index, generateGet(obj));
402: }
403:
404: /**
405: * Generates loading code
406: */
407: public int generateLoad(JavaWriter out, String rs, String indexVar,
408: int index) throws IOException {
409: if (_aliasKey != null)
410: return index;
411: /*
412: if (getSetterMethod() == null)
413: return index;
414: */
415:
416: String var = "amber_ld" + index;
417:
418: Type columnType;
419:
420: // jpa/0w24
421: if (getColumn() == null)
422: columnType = getType();
423: else
424: columnType = getColumn().getType();
425:
426: if (columnType instanceof ArrayType)
427: out.print(((ArrayType) columnType)
428: .getPrimitiveArrayTypeName());
429: else
430: out.print(getJavaTypeName());
431: out.print(" " + var + " = ");
432:
433: // jpa/0w24
434: if (getColumn() == null)
435: index = getType().generateLoad(out, rs, indexVar, index);
436: else
437: index = getColumn().generateLoad(out, rs, indexVar, index);
438:
439: out.println(";");
440:
441: // jpa/1417 as a negative test.
442: if (columnType instanceof ArrayType) {
443: ArrayType arrayType = (ArrayType) columnType;
444: String primitiveType = arrayType
445: .getPrimitiveArrayTypeName();
446:
447: out.print(getJavaTypeName() + " " + var + "_temp = null;");
448: out.println();
449:
450: // jpa/110d
451: out.print("if (" + var + " != null) {");
452: out.pushDepth();
453:
454: out.print(var + "_temp = new ");
455: String instanceJavaType = arrayType.getJavaObjectTypeName();
456: out.println(instanceJavaType + "[" + var + ".length];");
457: out.println("for (int i=0; i < " + var + ".length; i++)");
458: out.print(" " + var + "_temp[i] = new ");
459: out.print(instanceJavaType);
460: out.println("(" + var + "[i]);");
461:
462: out.popDepth();
463: out.println("}");
464:
465: out.println();
466: out.println(generateSuperSetter(var + "_temp") + ";");
467: } else
468: out.println(generateSuperSetter(var) + ";");
469:
470: // out.println("__caucho_loadMask |= " + (1L << getIndex()) + "L;");
471:
472: return index;
473: }
474:
475: /**
476: * Creates the expression for the field.
477: */
478: public AmberExpr createExpr(QueryParser parser, PathExpr parent) {
479: Column column;
480:
481: if (parent instanceof EmbeddedExpr) {
482: column = ((EmbeddedExpr) parent)
483: .getColumnByFieldName(getName());
484: } else
485: column = getColumn();
486:
487: return new ColumnExpr(parent, column);
488: }
489: }
|