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.KeyManyToOneExpr;
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.table.ForeignColumn;
037: import com.caucho.amber.table.LinkColumns;
038: import com.caucho.amber.type.EntityType;
039: import com.caucho.amber.type.RelatedType;
040: import com.caucho.amber.type.Type;
041: import com.caucho.config.ConfigException;
042: import com.caucho.java.JavaWriter;
043: import com.caucho.log.Log;
044: import com.caucho.util.CharBuffer;
045: import com.caucho.util.L10N;
046:
047: import java.io.IOException;
048: import java.util.ArrayList;
049: import java.util.HashSet;
050: import java.util.logging.Logger;
051:
052: /**
053: * Configuration for a bean's field
054: */
055: public class KeyManyToOneField extends EntityManyToOneField implements
056: IdField {
057: private static final L10N L = new L10N(KeyManyToOneField.class);
058: protected static final Logger log = Log
059: .open(KeyManyToOneField.class);
060:
061: // fields
062: private ArrayList<KeyPropertyField> _idFields = new ArrayList<KeyPropertyField>();
063:
064: // use field accessors to get key values.
065: private boolean _isKeyField;
066:
067: public KeyManyToOneField(RelatedType entityType, String name)
068: throws ConfigException {
069: super (entityType, name);
070: }
071:
072: public KeyManyToOneField(RelatedType entityType, String name,
073: LinkColumns columns) throws ConfigException {
074: super (entityType, name);
075:
076: setLinkColumns(columns);
077:
078: setSourceCascadeDelete(true);
079: }
080:
081: /**
082: * Gets the generator.
083: */
084: public String getGenerator() {
085: return null;
086: }
087:
088: /**
089: * Returns the target type as entity (ejb 2.1)
090: * See com.caucho.ejb.ql.Expr
091: */
092: public EntityType getEntityType() {
093: return (EntityType) getEntityTargetType();
094: }
095:
096: public Type getType() {
097: return getEntityTargetType();
098: }
099:
100: public Column getColumn() {
101: throw new UnsupportedOperationException();
102: }
103:
104: /**
105: * Returns true for a generator.
106: */
107: public boolean isAutoGenerate() {
108: return false;
109: }
110:
111: /**
112: * Set true if key fields are accessed through fields.
113: */
114: public void setKeyField(boolean isKeyField) {
115: _isKeyField = isKeyField;
116: }
117:
118: /**
119: * Returns the foreign type name.
120: */
121: public String getForeignTypeName() {
122: return getJavaTypeName();
123: }
124:
125: /**
126: * Set true if deletes cascade to the target.
127: */
128: public boolean isTargetCascadeDelete() {
129: return false;
130: }
131:
132: /**
133: * Set true if deletes cascade to the source.
134: */
135: public boolean isSourceCascadeDelete() {
136: return true;
137: }
138:
139: /**
140: * Initialize the field.
141: */
142: public void init() throws ConfigException {
143: super .init();
144:
145: ArrayList<IdField> keys = getEntityTargetType().getId()
146: .getKeys();
147:
148: ArrayList<ForeignColumn> columns = getLinkColumns()
149: .getColumns();
150:
151: for (int i = 0; i < keys.size(); i++) {
152: IdField key = keys.get(i);
153: ForeignColumn column = columns.get(i);
154:
155: KeyPropertyField field;
156: field = new IdentifyingKeyPropertyField(
157: getEntitySourceType(), column);
158:
159: _idFields.add(field);
160: }
161: }
162:
163: /**
164: * Returns the component count.
165: */
166: public int getComponentCount() {
167: return getEntityTargetType().getId().getKeyCount();
168: }
169:
170: /**
171: * Returns columns
172: */
173: public ArrayList<Column> getColumns() {
174: ArrayList<Column> columns = new ArrayList<Column>();
175:
176: columns.addAll(getLinkColumns().getColumns());
177:
178: return columns;
179: }
180:
181: /**
182: * Returns the identifying field matching the target's id.
183: */
184: public KeyPropertyField getIdField(IdField field) {
185: ArrayList<IdField> keys = getEntityTargetType().getId()
186: .getKeys();
187:
188: if (_idFields.size() != keys.size()) {
189: try {
190: init();
191: } catch (Exception e) {
192: throw new RuntimeException(e);
193: }
194: }
195:
196: for (int i = 0; i < keys.size(); i++) {
197: if (keys.get(i) == field)
198: return _idFields.get(i);
199: }
200:
201: throw new IllegalStateException(field.toString());
202: }
203:
204: /**
205: * Creates the expression for the field.
206: */
207: public AmberExpr createExpr(QueryParser parser, PathExpr parent) {
208: return new KeyManyToOneExpr(parent, this );
209: }
210:
211: /**
212: * Returns the where code
213: */
214: public String generateMatchArgWhere(String id) {
215: return getLinkColumns().generateMatchArgSQL(id);
216: }
217:
218: /**
219: * Returns the where code
220: */
221: public String generateRawWhere(String id) {
222: CharBuffer cb = new CharBuffer();
223:
224: String prefix = id + "." + getName();
225:
226: ArrayList<IdField> keys = getEntityTargetType().getId()
227: .getKeys();
228:
229: for (int i = 0; i < keys.size(); i++) {
230: if (i != 0)
231: cb.append(" and ");
232:
233: cb.append(keys.get(i).generateRawWhere(prefix));
234: }
235:
236: return cb.toString();
237: }
238:
239: /**
240: * Generates the property getter for an EJB proxy
241: *
242: * @param value the non-null value
243: */
244: public String generateGetProxyProperty(String value) {
245: throw new UnsupportedOperationException();
246: }
247:
248: /**
249: * Generates the linking for a join
250: */
251: public void generateJoin(CharBuffer cb, String table1, String table2) {
252: cb.append(getLinkColumns().generateJoin(table1, table2));
253: }
254:
255: /**
256: * Gets the column corresponding to the target field.
257: */
258: public ForeignColumn getColumn(Column key) {
259: return getLinkColumns().getSourceColumn(key);
260: }
261:
262: /**
263: * Returns the foreign type.
264: */
265: public int generateLoadForeign(JavaWriter out, String rs,
266: String indexVar, int index) throws IOException {
267: return generateLoadForeign(out, rs, indexVar, index,
268: getForeignTypeName().replace('.', '_'));
269: }
270:
271: /**
272: * Returns the actual data.
273: */
274: public String generateSuperGetter() {
275: if (isAbstract() || getGetterMethod() == null)
276: return getFieldName();
277: else
278: return getGetterMethod().getName() + "()";
279: }
280:
281: /**
282: * Sets the actual data.
283: */
284: public String generateSuperSetter(String objThis, String value) {
285: if (isAbstract() || getGetterMethod() == null
286: || getSetterMethod() == null)
287: return objThis + '.' + getFieldName() + " = " + value + ";";
288: else
289: return objThis + '.' + getSetterMethod().getName() + "("
290: + value + ")";
291: }
292:
293: /**
294: * Generates code to copy to an object.
295: */
296: public void generateCopy(JavaWriter out, String dest, String source)
297: throws IOException {
298: out.println(generateSet(dest, generateGet(source)) + ";");
299: }
300:
301: /**
302: * Returns the foreign type.
303: */
304: public int generateLoadForeign(JavaWriter out, String rs,
305: String indexVar, int index, String name) throws IOException {
306: out.print("(" + getForeignTypeName() + ") ");
307:
308: out.print("aConn.loadProxy(\""
309: + getEntityTargetType().getName() + "\", ");
310: index = getEntityTargetType().getId().generateLoadForeign(out,
311: rs, indexVar, index, getName());
312:
313: out.println(");");
314:
315: return index;
316: }
317:
318: /**
319: * Generates any prologue.
320: */
321: public void generatePrologue(JavaWriter out,
322: HashSet<Object> completedSet) throws IOException {
323: super .generatePrologue(out, completedSet);
324:
325: if (isAbstract()) {
326: out.println();
327:
328: out.println();
329: out.println("public " + getJavaTypeName() + " "
330: + getGetterName() + "()");
331: out.println("{");
332: out.println(" return " + getFieldName() + ";");
333: out.println("}");
334:
335: out.println();
336: out.println("public void " + getSetterName() + "("
337: + getJavaTypeName() + " v)");
338: out.println("{");
339: out.println(" " + getFieldName() + " = v;");
340: out.println("}");
341: }
342: }
343:
344: /**
345: * Generates the set clause.
346: */
347: public void generateSet(JavaWriter out, String pstmt, String index,
348: String value) throws IOException {
349: ArrayList<ForeignColumn> columns = getLinkColumns()
350: .getColumns();
351:
352: Id id = getEntityTargetType().getId();
353: ArrayList<IdField> keys = id.getKeys();
354:
355: String prop = value != null ? generateGet(value) : null;
356: for (int i = 0; i < columns.size(); i++) {
357: IdField key = keys.get(i);
358: ForeignColumn column = columns.get(i);
359:
360: column
361: .generateSet(out, pstmt, index, key
362: .generateGet(prop));
363: }
364: }
365:
366: /**
367: * Generates the set clause.
368: */
369: public void generateSet(JavaWriter out, String pstmt, String index)
370: throws IOException {
371: String var = getFieldName();
372:
373: Id id = getEntityTargetType().getId();
374: ArrayList<IdField> keys = id.getKeys();
375:
376: for (int i = 0; i < keys.size(); i++) {
377: IdField key = keys.get(i);
378:
379: key.getType().generateSet(out, pstmt, index,
380: key.generateGet(var));
381: }
382: }
383:
384: /**
385: * Generates the set clause.
386: */
387: public void generateSetInsert(JavaWriter out, String pstmt,
388: String index) throws IOException {
389: String value = generateSuperGetter();
390:
391: out.println("if ("
392: + getEntityTargetType().generateIsNull(value) + ") {");
393: out.pushDepth();
394:
395: getEntityTargetType().generateSetNull(out, pstmt, index);
396:
397: out.popDepth();
398: out.println("} else {");
399: out.pushDepth();
400:
401: generateSet(out, pstmt, index);
402:
403: out.popDepth();
404: out.println("}");
405: }
406:
407: /**
408: * Generates the setter for a key property
409: */
410: public String generateSetKeyProperty(String key, String value)
411: throws IOException {
412: if (_isKeyField)
413: return key + "." + getName() + " = " + value;
414: else
415: return generateSet(key, value);
416: }
417:
418: /**
419: * Generates the getter for a key property
420: */
421: public String generateGetKeyProperty(String key) throws IOException {
422: if (_isKeyField)
423: return key + "." + getName();
424: else
425: return generateGet(key);
426: }
427:
428: /**
429: * Generates the set clause.
430: */
431: public void generateSetGeneratedKeys(JavaWriter out, String pstmt)
432: throws IOException {
433: }
434:
435: /**
436: * Generates the set clause.
437: */
438: public void generateCheckCreateKey(JavaWriter out)
439: throws IOException {
440: out.println("if (" + generateSuperGetter() + " == null)");
441: out
442: .println(" throw new com.caucho.amber.AmberException(\"primary key must not be null on creation. "
443: + getGetterName()
444: + "() must not return null.\");");
445: }
446:
447: /**
448: * Returns a test for null.
449: */
450: public String generateIsNull(String value) {
451: return "(" + value + " == null)";
452: }
453:
454: /**
455: * Converts from an object.
456: */
457: public String toValue(String value) {
458: return "((" + getJavaTypeName() + ") " + value + ")";
459: }
460: }
|