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: * Free Software Foundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.amber.field;
030:
031: import com.caucho.amber.expr.AmberExpr;
032: import com.caucho.amber.expr.KeyColumnExpr;
033: import com.caucho.amber.expr.PathExpr;
034: import com.caucho.amber.query.QueryParser;
035: import com.caucho.amber.table.Column;
036: import com.caucho.amber.type.RelatedType;
037: import com.caucho.amber.type.Type;
038: import com.caucho.bytecode.JClassWrapper;
039: import com.caucho.config.ConfigException;
040: import com.caucho.java.JavaWriter;
041: import com.caucho.log.Log;
042: import com.caucho.util.L10N;
043:
044: import java.io.IOException;
045: import java.lang.reflect.Method;
046: import java.util.ArrayList;
047: import java.util.HashSet;
048: import java.util.logging.Level;
049: import java.util.logging.Logger;
050:
051: /**
052: * Configuration for a bean's field
053: */
054: public class KeyPropertyField extends PropertyField implements IdField {
055: private static final L10N L = new L10N(KeyPropertyField.class);
056: protected static final Logger log = Log
057: .open(KeyPropertyField.class);
058:
059: private Column _column;
060: private boolean _isKeyField;
061: private String _generator;
062:
063: public KeyPropertyField(RelatedType tableType) {
064: super (tableType);
065: }
066:
067: public KeyPropertyField(RelatedType tableType, String name)
068: throws ConfigException {
069: super (tableType, name);
070: }
071:
072: public KeyPropertyField(RelatedType entityType, String name,
073: Column column) throws ConfigException {
074: super (entityType, name);
075:
076: _column = column;
077: _column.setPrimaryKey(true);
078: }
079:
080: /**
081: * Returns true if key fields are accessed through fields.
082: */
083: public boolean isKeyField() {
084: return _isKeyField;
085: }
086:
087: /**
088: * Set true if key fields are accessed through fields.
089: */
090: public void setKeyField(boolean isKeyField) {
091: _isKeyField = isKeyField;
092: }
093:
094: /**
095: * Sets the generator.
096: */
097: public void setGenerator(String generator) {
098: _generator = generator;
099:
100: if (_column != null)
101: _column.setGeneratorType(generator);
102: }
103:
104: /**
105: * Gets the generator.
106: */
107: public String getGenerator() {
108: return _generator;
109: }
110:
111: /**
112: * Returns true for a generator.
113: */
114: public boolean isAutoGenerate() {
115: return _generator != null;
116: }
117:
118: /**
119: * Sets the column
120: */
121: public void setColumn(Column column) {
122: _column = column;
123: _column.setPrimaryKey(true);
124: }
125:
126: /**
127: * Returns column
128: */
129: public Column getColumn() {
130: return _column;
131: }
132:
133: /**
134: * Returns columns
135: */
136: public ArrayList<Column> getColumns() {
137: ArrayList<Column> columns = new ArrayList<Column>();
138:
139: columns.add(_column);
140:
141: return columns;
142: }
143:
144: /**
145: * Returns the component count.
146: */
147: public int getComponentCount() {
148: return 1;
149: }
150:
151: /**
152: * Returns type
153: */
154: public Type getType() {
155: return _column.getType();
156: }
157:
158: /**
159: * Returns the foreign type.
160: */
161: public String getForeignTypeName() {
162: // jpa/0gg2
163: if (_column == null)
164: return "";
165:
166: return _column.getType().getForeignTypeName();
167: }
168:
169: /**
170: * Generates any prologue.
171: */
172: public void generatePrologue(JavaWriter out,
173: HashSet<Object> completedSet) throws IOException {
174: super .generatePrologue(out, completedSet);
175:
176: if (isAbstract()) {
177: out.println();
178:
179: out.println();
180: out.println("public " + getJavaTypeName() + " "
181: + getGetterName() + "()");
182: out.println("{");
183: out.println(" return " + getFieldName() + ";");
184: out.println("}");
185:
186: out.println();
187: out.println("public void " + getSetterName() + "("
188: + getJavaTypeName() + " v)");
189: out.println("{");
190: out.println(" " + getFieldName() + " = v;");
191: out.println("}");
192: }
193: }
194:
195: /**
196: * Returns the actual data.
197: */
198: public String generateSuperGetter() {
199: if (isAbstract() || getGetterMethod() == null)
200: return getFieldName();
201: else
202: return getGetterMethod().getName() + "()";
203: }
204:
205: /**
206: * Sets the actual data.
207: */
208: public String generateSuperSetter(String objThis, String value) {
209: if (isAbstract() || getGetterMethod() == null
210: || getSetterMethod() == null)
211: return objThis + "." + getFieldName() + " = " + value + ";";
212: else
213: return objThis + "." + getSetterMethod().getName() + "("
214: + value + ")";
215: }
216:
217: /**
218: * Generates code to copy to an object.
219: */
220: public void generateCopy(JavaWriter out, String dest, String source)
221: throws IOException {
222: throw new UnsupportedOperationException();
223: }
224:
225: /**
226: * Returns the select code
227: */
228: public String generateSelect(String id) {
229: return _column.generateSelect(id);
230: }
231:
232: /**
233: * Returns the JPA QL select code
234: */
235: public String generateJavaSelect(String id) {
236: String select = getName();
237:
238: if (id != null)
239: select = id + "." + select;
240:
241: return select;
242: }
243:
244: /**
245: * Returns the where code
246: */
247: public String generateMatchArgWhere(String id) {
248: return _column.generateMatchArgWhere(id);
249: }
250:
251: /**
252: * Returns the where code
253: */
254: public String generateRawWhere(String id) {
255: return id + "." + getName() + "=?";
256: }
257:
258: /**
259: * Returns the foreign type.
260: */
261: public int generateLoadForeign(JavaWriter out, String rs,
262: String indexVar, int index) throws IOException {
263: return generateLoadForeign(out, rs, indexVar, index,
264: getForeignTypeName().replace('.', '_'));
265: }
266:
267: /**
268: * Generates loading cache
269: */
270: public void generateLoadFromObject(JavaWriter out, String obj)
271: throws IOException {
272: out.println(generateSuperSetter(generateGet(obj)) + ";");
273: }
274:
275: /**
276: * Generates loading cache
277: */
278: public String generateSetNull(String obj) throws IOException {
279: return generateSet(obj, getColumn().getType().generateNull());
280: }
281:
282: /**
283: * Returns a test for null.
284: */
285: public String generateIsNull(String value) {
286: return "(" + getType().generateIsNull(generateSuperGetter())
287: + ")";
288: }
289:
290: /**
291: * Returns the foreign type.
292: */
293: public int generateLoadForeign(JavaWriter out, String rs,
294: String indexVar, int index, String name) throws IOException {
295: // XXX: 0 == null
296: return _column.getType().generateLoadForeign(out, rs, indexVar,
297: index);
298: }
299:
300: /**
301: * Generates the set clause.
302: */
303: public void generateSet(JavaWriter out, String pstmt, String index,
304: String value) throws IOException {
305: if (value == null)
306: _column.getType().generateSetNull(out, pstmt, index);
307: else
308: _column.getType().generateSet(out, pstmt, index,
309: generateGet(value));
310: }
311:
312: /**
313: * Generates code for a match.
314: */
315: public void generateMatch(JavaWriter out, String key)
316: throws IOException {
317: out.println("return " + generateEquals("super", key) + ";");
318: }
319:
320: /**
321: * Generates code to test the equals.
322: */
323: public String generateEquals(String left, String right) {
324: return _column.getType().generateEquals(left, right);
325: }
326:
327: /**
328: * Generates the set clause.
329: */
330: public void generateSetInsert(JavaWriter out, String pstmt,
331: String index) throws IOException {
332: String value = generateSuperGetter();
333:
334: if (isAutoGenerate()) {
335: out.println("if (" + getType().generateIsNull(value)
336: + ") {");
337: out.pushDepth();
338:
339: getType().generateSetNull(out, pstmt, index);
340:
341: out.popDepth();
342: out.println("} else {");
343: out.pushDepth();
344:
345: generateSet(out, pstmt, index);
346:
347: out.popDepth();
348: out.println("}");
349: } else
350: generateSet(out, pstmt, index);
351: }
352:
353: /**
354: * Generates the set clause.
355: */
356: public void generateCheckCreateKey(JavaWriter out)
357: throws IOException {
358: /*
359: out.println("insertSql.append(\"" + getName() + "\");");
360: out.println("insertValues.append(\"?\");");
361: */
362:
363: if ("identity".equals(_generator))
364: return;
365: else if (_generator != null) {
366: if (getEntitySourceType().getGenerator(getName()) == null)
367: throw new IllegalStateException(
368: "no sequence generator for " + getName());
369:
370: out.println("if ("
371: + getType().generateIsNull(generateSuperGetter())
372: + ") {");
373: out.pushDepth();
374:
375: String id = "home.nextGeneratorId(aConn, \"" + getName()
376: + "\")";
377:
378: String javaType = getType().getJavaTypeName();
379:
380: if ("long".equals(javaType))
381: id = "(" + javaType + ") " + id;
382: else if ("int".equals(javaType))
383: id = "(" + javaType + ") " + id;
384: else if ("short".equals(javaType))
385: id = "(" + javaType + ") " + id;
386: else if ("java.lang.Long".equals(javaType))
387: id = "new Long(" + id + ")";
388: else if ("java.lang.Integer".equals(javaType))
389: id = "new Integer((int) " + id + ")";
390: else if ("java.lang.Short".equals(javaType))
391: id = "new Short((short) " + id + ")";
392: else if ("java.lang.Byte".equals(javaType))
393: id = "new Byte((byte) " + id + ")";
394: else
395: throw new UnsupportedOperationException(L.l(
396: "{0} is an unsupported generated key type.",
397: javaType));
398:
399: out.println(generateSuperSetter(id) + ";");
400:
401: out.popDepth();
402: out.println("}");
403:
404: return;
405: }
406:
407: if (!getJavaType().isPrimitive()) {
408: out.println("if ("
409: + getType().generateIsNull(generateSuperGetter())
410: + ")");
411: out
412: .println(" throw new com.caucho.amber.AmberException(\"primary key must not be null on creation. "
413: + getGetterName()
414: + "() must not return null.\");");
415: }
416: }
417:
418: /**
419: * Generates the set clause.
420: */
421: public void generateSetGeneratedKeys(JavaWriter out, String pstmt)
422: throws IOException {
423: if (!"identity".equals(_generator))
424: return;
425:
426: out.print("if (");
427: out.print(getType().generateIsNull(generateSuperGetter()));
428: out.println(") {");
429: out.pushDepth();
430:
431: String var = "__caucho_rs_" + out.generateId();
432:
433: out.println("java.sql.ResultSet " + var + " = " + pstmt
434: + ".getGeneratedKeys();");
435: out.println("if (" + var + ".next()) {");
436: out.pushDepth();
437:
438: out.print(getType().getName() + " v1 = ");
439: getType().generateLoad(out, var, "", 1);
440: out.println(";");
441:
442: out.println(generateSuperSetter("v1") + ";");
443:
444: out
445: .println("if (__caucho_log.isLoggable(java.util.logging.Level.FINER))");
446: out
447: .println(" __caucho_log.finer(\"create with new primaryKey \" + "
448: + generateSuperGetter() + ");");
449:
450: out.popDepth();
451: out.println("}");
452: out.println("else throw new java.sql.SQLException();");
453:
454: out.popDepth();
455: out.println("}");
456: }
457:
458: /**
459: * Generates the setter for a key property
460: */
461: public String generateSetKeyProperty(String key, String value)
462: throws IOException {
463: if (_isKeyField)
464: return key + "." + getName() + " = " + value;
465: else
466: return generateSet(key, value);
467: }
468:
469: /**
470: * Generates the getter for a key property
471: */
472: public String generateGetKeyProperty(String key) {
473: if (_isKeyField)
474: return key + "." + getName();
475: else
476: return generateGet(key);
477: }
478:
479: /**
480: * Generates the property getter for an EJB proxy
481: *
482: * @param value the non-null value
483: */
484: public String generateGetProxyProperty(String value) {
485: // XXX: better solution
486: Class proxyClass = ((JClassWrapper) getEntitySourceType()
487: .getProxyClass()).getWrappedClass();
488:
489: try {
490: Method method = proxyClass.getMethod(getGetterName(),
491: new Class[0]);
492:
493: if (method != null)
494: return generateGet(value);
495: } catch (Throwable e) {
496: log.log(Level.FINER, e.toString(), e);
497: }
498:
499: Id id = getEntitySourceType().getId();
500:
501: return generateGetKeyProperty("((" + id.getForeignTypeName()
502: + ") " + value + ".getPrimaryKey())");
503: }
504:
505: /**
506: * Creates the expression for the field.
507: */
508: public AmberExpr createExpr(QueryParser parser, PathExpr parent) {
509: return new KeyColumnExpr(parent, getColumn());
510: }
511:
512: /**
513: * Converts to an object.
514: */
515: public String toObject(String value) {
516: return getColumn().getType().toObject(value);
517: }
518:
519: /**
520: * Converts from an object.
521: */
522: public String toValue(String value) {
523: return getColumn().getType().generateCastFromObject(value);
524: }
525: }
|