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 Rodrigo Westrupp
028: */
029:
030: package com.caucho.amber.type;
031:
032: import com.caucho.amber.field.*;
033: import com.caucho.amber.manager.AmberPersistenceUnit;
034: import com.caucho.amber.table.Column;
035: import com.caucho.amber.table.Table;
036: import com.caucho.bytecode.JClass;
037: import com.caucho.bytecode.JClassDependency;
038: import com.caucho.bytecode.JField;
039: import com.caucho.bytecode.JMethod;
040: import com.caucho.config.ConfigException;
041: import com.caucho.java.JavaWriter;
042: import com.caucho.make.ClassDependency;
043: import com.caucho.util.CharBuffer;
044: import com.caucho.util.L10N;
045: import com.caucho.vfs.PersistentDependency;
046:
047: import java.io.IOException;
048: import java.util.ArrayList;
049: import java.util.Collections;
050: import java.util.HashMap;
051: import java.util.logging.Logger;
052:
053: /**
054: * Represents a stateful type:
055: * embeddable, entity or mapped-superclass.
056: */
057: abstract public class AbstractStatefulType extends AbstractEnhancedType {
058: private static final Logger log = Logger
059: .getLogger(AbstractStatefulType.class.getName());
060: private static final L10N L = new L10N(AbstractStatefulType.class);
061:
062: private boolean _isFieldAccess;
063:
064: private ArrayList<AmberField> _fields = new ArrayList<AmberField>();
065:
066: private ArrayList<AmberField> _mappedSuperclassFields = new ArrayList<AmberField>();
067:
068: private volatile boolean _isConfigured;
069:
070: private ArrayList<PersistentDependency> _dependencies = new ArrayList<PersistentDependency>();
071:
072: private HashMap<String, String> _completionFields = new HashMap<String, String>();
073:
074: private Column _discriminator;
075:
076: public AbstractStatefulType(
077: AmberPersistenceUnit amberPersistenceUnit) {
078: super (amberPersistenceUnit);
079: }
080:
081: /**
082: * Set true for field-access.
083: */
084: public void setFieldAccess(boolean isFieldAccess) {
085: _isFieldAccess = isFieldAccess;
086: }
087:
088: /**
089: * Set true for field-access.
090: */
091: public boolean isFieldAccess() {
092: return _isFieldAccess;
093: }
094:
095: /**
096: * Returns true for an embeddable
097: */
098: public boolean isEmbeddable() {
099: return false;
100: }
101:
102: /**
103: * Returns the discriminator.
104: */
105: public Column getDiscriminator() {
106: return _discriminator;
107: }
108:
109: /**
110: * Sets the discriminator.
111: */
112: public void setDiscriminator(Column discriminator) {
113: _discriminator = discriminator;
114: }
115:
116: /**
117: * Returns the java type.
118: */
119: public String getJavaTypeName() {
120: return getInstanceClassName();
121: }
122:
123: /**
124: * Adds a new field.
125: */
126: public void addField(AmberField field) {
127: _fields.add(field);
128: Collections.sort(_fields, new AmberFieldCompare());
129: }
130:
131: /**
132: * Returns the fields.
133: */
134: public ArrayList<AmberField> getFields() {
135: return _fields;
136: }
137:
138: /**
139: * Returns the field with a given name.
140: */
141: public AmberField getField(String name) {
142: for (int i = 0; i < _fields.size(); i++) {
143: AmberField field = _fields.get(i);
144:
145: if (field.getName().equals(name))
146: return field;
147: }
148:
149: return null;
150: }
151:
152: /**
153: * Adds a mapped superclass field.
154: */
155: public void addMappedSuperclassField(AmberField field) {
156: if (_mappedSuperclassFields.contains(field))
157: return;
158:
159: _mappedSuperclassFields.add(field);
160: Collections.sort(_mappedSuperclassFields,
161: new AmberFieldCompare());
162: }
163:
164: /**
165: * Returns the mapped superclass fields.
166: */
167: public ArrayList<AmberField> getMappedSuperclassFields() {
168: return _mappedSuperclassFields;
169: }
170:
171: /**
172: * Returns the mapped superclass field with a given name.
173: */
174: public AmberField getMappedSuperclassField(String name) {
175: for (int i = 0; i < _mappedSuperclassFields.size(); i++) {
176: AmberField field = _mappedSuperclassFields.get(i);
177:
178: if (field.getName().equals(name))
179: return field;
180: }
181:
182: return null;
183: }
184:
185: /**
186: * Sets the bean class.
187: */
188: public void setBeanClass(JClass beanClass) {
189: super .setBeanClass(beanClass);
190:
191: addDependency(_beanClass);
192: }
193:
194: /**
195: * Adds a dependency.
196: */
197: public void addDependency(Class cl) {
198: addDependency(new ClassDependency(cl));
199: }
200:
201: /**
202: * Adds a dependency.
203: */
204: public void addDependency(JClass cl) {
205: addDependency(new JClassDependency(cl));
206: }
207:
208: /**
209: * Adds a dependency.
210: */
211: public void addDependency(PersistentDependency depend) {
212: if (!_dependencies.contains(depend))
213: _dependencies.add(depend);
214: }
215:
216: /**
217: * Gets the dependency.
218: */
219: public ArrayList<PersistentDependency> getDependencies() {
220: return _dependencies;
221: }
222:
223: /**
224: * Adds a new completion field.
225: */
226: public void addCompletionField(String name) {
227: _completionFields.put(name, name);
228: }
229:
230: /**
231: * Returns true if and only if it has the completion field.
232: */
233: public boolean containsCompletionField(String completionField) {
234: return _completionFields.containsKey(completionField);
235: }
236:
237: /**
238: * Remove all completion fields.
239: */
240: public void removeAllCompletionFields() {
241: _completionFields.clear();
242: }
243:
244: /**
245: * Set true if configured.
246: */
247: public boolean startConfigure() {
248: synchronized (this ) {
249: if (_isConfigured)
250: return false;
251:
252: _isConfigured = true;
253:
254: return true;
255: }
256: }
257:
258: /**
259: * Initialize the type.
260: */
261: public void init() throws ConfigException {
262: }
263:
264: /**
265: * Converts the value.
266: */
267: public String generateCastFromObject(String value) {
268: return "((" + getInstanceClassName() + ") " + value + ")";
269: }
270:
271: /**
272: * Generates a string to load the field.
273: */
274: public int generateLoad(JavaWriter out, String rs, String indexVar,
275: int index, int loadGroupIndex,
276: ArrayList<AmberField> overriddenFields) throws IOException {
277: if (overriddenFields == null && getDiscriminator() != null) {
278: RelatedType parent = null;
279:
280: if (this instanceof RelatedType)
281: parent = ((RelatedType) this ).getParentType();
282:
283: boolean isAbstractParent = getPersistenceUnit().isJPA()
284: && (parent == null || parent.getBeanClass()
285: .isAbstract());
286:
287: if (loadGroupIndex == 0 || isAbstractParent)
288: index++;
289: }
290:
291: ArrayList<AmberField> fields = null;
292:
293: if (this instanceof RelatedType) {
294: fields = getMappedSuperclassFields();
295:
296: RelatedType parent = ((RelatedType) this ).getParentType();
297:
298: if (parent != null) {
299: // jpa/0l14
300: index = parent.generateLoad(out, rs, indexVar, index,
301: loadGroupIndex, fields);
302: }
303: }
304:
305: for (int i = 0; i < 2; i++) {
306: if (fields == null) {
307: fields = getFields();
308: continue;
309: }
310:
311: for (int j = 0; j < fields.size(); j++) {
312: AmberField field = fields.get(j);
313:
314: // jpa/0l14, jpa/0ge3
315: if (overriddenFields != null) {
316: boolean isOverridden = false;
317:
318: for (AmberField amberField : overriddenFields) {
319: if (amberField.getName()
320: .equals(field.getName()))
321: isOverridden = true;
322: }
323:
324: if (isOverridden)
325: continue;
326: }
327:
328: // ejb/0602
329: if (getPersistenceUnit().isJPA()) {
330: if (field instanceof EntityManyToOneField) {
331: ((EntityManyToOneField) field)
332: .init((RelatedType) this );
333: }
334: }
335:
336: // jpa/0gg3
337: if (field.getLoadGroupIndex() == loadGroupIndex)
338: index = field
339: .generateLoad(out, rs, indexVar, index);
340: }
341:
342: fields = getFields();
343: }
344:
345: return index;
346: }
347:
348: /**
349: * Generates the select clause for a load.
350: */
351: abstract public String generateLoadSelect(Table table, String id);
352:
353: /**
354: * Generates the select clause for a load.
355: */
356: public String generateLoadSelect(Table table, String id,
357: int loadGroup) {
358: return generateLoadSelect(table, id, loadGroup, false);
359: }
360:
361: /**
362: * Generates the select clause for a load.
363: */
364: public String generateLoadSelect(Table table, String id,
365: int loadGroup, boolean hasSelect) {
366: CharBuffer cb = CharBuffer.allocate();
367:
368: // jpa/0ge2
369: // jpa/0l14
370: /*
371: ArrayList<AmberField> fields = null;
372:
373: if (this instanceof RelatedType) {
374: fields = getMappedSuperclassFields();
375:
376: RelatedType parent = ((RelatedType) this).getParentType();
377:
378: if (parent != null) {
379: String parentSelect =
380: parent.generateLoadSelect(table, id, loadGroup,
381: hasSelect, fields);
382:
383: if (parentSelect != null) {
384: hasSelect = true;
385:
386: cb.append(parentSelect);
387: }
388: }
389: }
390: */
391:
392: // jpa/0l14, jpa/0ge3
393: for (AmberField field : getFields()) {
394: // ejb/0602
395: if (getPersistenceUnit().isJPA()) {
396: if (field instanceof EntityManyToOneField)
397: ((EntityManyToOneField) field)
398: .init((RelatedType) this );
399: }
400:
401: // jpa/0gg3
402: if (field.getLoadGroupIndex() == loadGroup) {
403: String propSelect = field.generateLoadSelect(table, id);
404:
405: if (propSelect == null)
406: continue;
407:
408: if (hasSelect)
409: cb.append(", ");
410: hasSelect = true;
411:
412: cb.append(propSelect);
413: }
414: }
415:
416: if (cb.length() == 0)
417: return null;
418: else
419: return cb.close();
420: }
421:
422: /**
423: * Generates the foreign delete
424: */
425: public void generateInvalidateForeign(JavaWriter out)
426: throws IOException {
427: for (AmberField field : getFields()) {
428: field.generateInvalidateForeign(out);
429: }
430: }
431:
432: /**
433: * Generates any expiration code.
434: */
435: public void generateExpire(JavaWriter out) throws IOException {
436: for (AmberField field : getFields()) {
437: field.generateExpire(out);
438: }
439: }
440:
441: /**
442: * Gets a matching getter.
443: */
444: public JMethod getGetter(String name) {
445: return getGetter(_beanClass, name);
446: }
447:
448: /**
449: * Gets a matching getter.
450: */
451: public static JMethod getGetter(JClass cl, String name) {
452: JMethod[] methods = cl.getMethods();
453:
454: for (int i = 0; i < methods.length; i++) {
455: JClass[] param = methods[i].getParameterTypes();
456: String methodName = methods[i].getName();
457:
458: if (name.equals(methodName) && param.length == 0)
459: return methods[i];
460: }
461:
462: cl = cl.getSuperClass();
463:
464: if (cl != null)
465: return getGetter(cl, name);
466: else
467: return null;
468: }
469:
470: /**
471: * Gets a matching getter.
472: */
473: public static JField getField(JClass cl, String name) {
474: JField[] fields = cl.getDeclaredFields();
475:
476: for (int i = 0; i < fields.length; i++) {
477: if (name.equals(fields[i].getName()))
478: return fields[i];
479: }
480:
481: cl = cl.getSuperClass();
482:
483: if (cl != null)
484: return getField(cl, name);
485: else
486: return null;
487: }
488:
489: /**
490: * Gets a matching getter.
491: */
492: public static JMethod getSetter(JClass cl, String name) {
493: JMethod[] methods = cl.getMethods();
494:
495: for (int i = 0; i < methods.length; i++) {
496: JClass[] param = methods[i].getParameterTypes();
497: String methodName = methods[i].getName();
498:
499: if (name.equals(methodName) && param.length == 1)
500: return methods[i];
501: }
502:
503: cl = cl.getSuperClass();
504:
505: if (cl != null)
506: return getSetter(cl, name);
507: else
508: return null;
509: }
510:
511: /**
512: * Returns the load mask generated on create.
513: */
514: public long getCreateLoadMask(int group) {
515: long mask = 0;
516:
517: for (int i = 0; i < _fields.size(); i++) {
518: mask |= _fields.get(i).getCreateLoadMask(group);
519: }
520:
521: return mask;
522: }
523:
524: /**
525: * Printable version of the entity.
526: */
527: public String toString() {
528: return "AbstractStatefulType[" + _beanClass.getName() + "]";
529: }
530: }
|