0001: /**
0002: * Objective Database Abstraction Layer (ODAL)
0003: * Copyright (c) 2004, The ODAL Development Group
0004: * All rights reserved.
0005: * For definition of the ODAL Development Group please refer to LICENCE.txt file
0006: *
0007: * Distributable under LGPL license.
0008: * See terms of license at gnu.org.
0009: */package com.completex.objective.components.persistency;
0010:
0011: import com.completex.objective.components.persistency.core.Join;
0012: import com.completex.objective.components.persistency.core.impl.JoinImpl;
0013: import com.completex.objective.components.persistency.key.impl.DefaultNaturalKeyFactory;
0014: import com.completex.objective.util.TypeUtil;
0015:
0016: import java.io.Serializable;
0017: import java.util.ArrayList;
0018: import java.util.Iterator;
0019: import java.util.List;
0020: import java.util.Map;
0021:
0022: /**
0023: * @author Gennady Krizhevsky
0024: */
0025: public abstract class AbstractPersistentObject implements Cloneable,
0026: Parent, DelegatingPersistentObjectFactory, Compound,
0027: Serializable {
0028: public static final String KEY_SEP = ":";
0029:
0030: static final long serialVersionUID = 1L;
0031:
0032: private transient boolean _compoundCascadeInsert = true;
0033: private transient boolean _compoundCascadeDelete = true;
0034: private transient ImplicitJoinMode _implicitJoinMode;
0035: //
0036: // Compound object related:
0037: //
0038: private transient Join _join;
0039: private transient boolean useColumnNames = true;
0040: private transient boolean useSelectStar = true;
0041: private transient boolean fromCache;
0042:
0043: protected transient PersistentObject[] persistentObjects;
0044: protected transient DelegatePersistentObjectFactory delegateFactory;
0045:
0046: private String mappingType;
0047:
0048: /**
0049: * Sets <tt>DelegatePersistentObjectFactory</tt>. If set it will be used when retrieving
0050: * result sets instead of default object factory (which normally object itself)
0051: *
0052: * @param delegateFactory
0053: */
0054: public void registerDelegateFactory(
0055: DelegatePersistentObjectFactory delegateFactory) {
0056: this .delegateFactory = delegateFactory;
0057: }
0058:
0059: /**
0060: * Returns <tt>DelegatePersistentObjectFactory</tt>
0061: *
0062: * @return <tt>DelegatePersistentObjectFactory</tt>
0063: */
0064: public DelegatePersistentObjectFactory delegateFactory() {
0065: return this .delegateFactory;
0066: }
0067:
0068: /**
0069: * Returns true if this object has been modified
0070: *
0071: * @return true if this object has been modified
0072: */
0073: public boolean dirty() {
0074: if (compound()) {
0075: PersistentObject[] persistentObjects = compoundEntries();
0076: for (int i = 0; i < persistentObjects.length; i++) {
0077: PersistentObject persistentObject = persistentObjects[i];
0078: if (persistentObject != null) {
0079: if (persistentObject.record().isDirty()) {
0080: return true;
0081: }
0082: }
0083: }
0084: } else {
0085: if (((PersistentObject) this ).record().isDirty()) {
0086: return true;
0087: }
0088: }
0089: return false;
0090: }
0091:
0092: /**
0093: * Returns true if cascade insert is to be performed based on entries joins
0094: * for entry specified by index parameter
0095: *
0096: * @param index index of entry
0097: * @return true if cascade insert is to be performed based on entries joins
0098: * for entry specified by index parameter
0099: */
0100: public boolean compoundCascadeInsert(int index) {
0101: return persistentObjects[index].compoundCascadeInsert();
0102: }
0103:
0104: /**
0105: * Sets flag to indicate if cascade insert is to be performed based on entries joins
0106: * for entry specified by index parameter
0107: *
0108: * @param index index of entry
0109: * @param compoundCascadeInsert flag to indicate if cascade insert is to be performed based on entries joins
0110: * for entry specified by index parameter
0111: */
0112: public void compoundCascadeInsert(int index,
0113: boolean compoundCascadeInsert) {
0114: persistentObjects[index]
0115: .compoundCascadeInsert(compoundCascadeInsert);
0116: }
0117:
0118: /**
0119: * Returns true if cascade delete is to be performed based on entries joins
0120: * for entry specified by index parameter
0121: *
0122: * @param index index of entry
0123: * @return true if cascade delete is to be performed based on entries joins
0124: * for entry specified by index parameter
0125: */
0126: public boolean compoundCascadeDelete(int index) {
0127: return persistentObjects[index].compoundCascadeDelete();
0128: }
0129:
0130: /**
0131: * Sets flag to indicate if cascade delete is to be performed based on entries joins
0132: * for entry specified by index parameter
0133: *
0134: * @param index index of entry
0135: * @param compoundCascadeDelete flag to indicate if cascade delete is to be performed based on entries joins
0136: * for entry specified by index parameter
0137: */
0138: public void compoundCascadeDelete(int index,
0139: boolean compoundCascadeDelete) {
0140: persistentObjects[index]
0141: .compoundCascadeDelete(compoundCascadeDelete);
0142: }
0143:
0144: /**
0145: * Sets both delete and insert cascade flags to true
0146: *
0147: * @param index index of entry
0148: */
0149: public void compoundCascadeAll(int index) {
0150: compoundCascadeInsert(index, true);
0151: compoundCascadeDelete(index, true);
0152: }
0153:
0154: /**
0155: * Unsets both delete and insert cascade flags to true
0156: *
0157: * @param index index of entry
0158: */
0159: public void compoundUncascadeAll(int index) {
0160: compoundCascadeInsert(index, false);
0161: compoundCascadeDelete(index, false);
0162: }
0163:
0164: /**
0165: * Returns true if cascade insert is to be performed based on entries joins
0166: *
0167: * @return true if cascade insert is to be performed based on entries joins
0168: */
0169: public boolean compoundCascadeInsert() {
0170: return _compoundCascadeInsert;
0171: }
0172:
0173: /**
0174: * Sets true if cascade insert is to be performed based on entries joins
0175: *
0176: * @param compoundCascadeInsert true if cascade insert is to be performed based on entries joins
0177: */
0178: protected void compoundCascadeInsert(boolean compoundCascadeInsert) {
0179: this ._compoundCascadeInsert = compoundCascadeInsert;
0180: }
0181:
0182: /**
0183: * Returns true if cascade delete is to be performed based on entries joins
0184: *
0185: * @return true if cascade delete is to be performed based on entries joins
0186: */
0187: public boolean compoundCascadeDelete() {
0188: return _compoundCascadeDelete;
0189: }
0190:
0191: /**
0192: * Sets true if cascade delete is to be performed based on entries joins
0193: *
0194: * @param compoundCascadeDelete true if cascade delete is to be performed based on entries joins
0195: */
0196: protected void compoundCascadeDelete(boolean compoundCascadeDelete) {
0197: this ._compoundCascadeDelete = compoundCascadeDelete;
0198: }
0199:
0200: /**
0201: * Factory method
0202: *
0203: * @return new instance of this object preserving tracing mode
0204: */
0205: public abstract AbstractPersistentObject newPersistentInstance();
0206:
0207: /**
0208: * Returns <tt>Parameters</tt> object based on values and column types of the record for columns with indeces
0209: * specified with "indeces" parameter. This method will populate parameters regardless of whether they are
0210: * "dirty" flags or nulls
0211: *
0212: * @param indeces
0213: * @return Parameters object based on values and column types of the record for columns with indeces
0214: * specified with "indeces" parameter
0215: */
0216: public abstract Parameters toParameters(int[] indeces);
0217:
0218: /**
0219: * Assembles <tt>LinkDependencyGraph</tt> associated with this <tt>PersistentObject</tt>
0220: */
0221: public abstract void assemble();
0222:
0223: /**
0224: * Returns <tt>Link</tt> reperesentation of this <tt>PersistentObject</tt>
0225: *
0226: * @return Link reperesentation of this Record
0227: */
0228: public abstract Link toLink();
0229:
0230: public static double Number2double(Number number) {
0231: return TypeUtil.Number2double(number);
0232: }
0233:
0234: public static long Number2long(Number number) {
0235: return TypeUtil.Number2long(number);
0236: }
0237:
0238: public static Double double2Number(double value) {
0239: return TypeUtil.double2Double(value);
0240: }
0241:
0242: public static Long long2Number(long value) {
0243: return TypeUtil.long2Long(value);
0244: }
0245:
0246: public static Boolean boolean2Boolean(boolean value) {
0247: return TypeUtil.boolean2Boolean(value);
0248: }
0249:
0250: public static boolean Boolean2boolean(Boolean value) {
0251: return TypeUtil.Boolean2boolean(value);
0252: }
0253:
0254: public Object clone() {
0255: try {
0256: return (AbstractPersistentObject) super .clone();
0257: } catch (CloneNotSupportedException e) {
0258: throw new OdalRuntimePersistencyException(
0259: "Cannot clone PersistentObject by class name ["
0260: + this .getClass().getName() + "]", e);
0261: }
0262: }
0263:
0264: /**
0265: * Method used in Tracing Collections as a key to determine which objects get modified.
0266: * Cen be used for object caching as well.
0267: *
0268: * @return key of this object
0269: * @see com.completex.objective.components.persistency.type.TracingCollection
0270: */
0271: public Object toKey() {
0272: return DefaultNaturalKeyFactory.naturalKey(this );
0273: }
0274:
0275: //
0276: // Compound begin:
0277: //
0278:
0279: /**
0280: * Returns true if this object is compound
0281: *
0282: * @return true if this object is compound
0283: */
0284: public boolean compound() {
0285: return false;
0286: }
0287:
0288: /**
0289: * Makes this object compound.
0290: *
0291: * @param size number of persistent entries
0292: */
0293: protected void compound(int size) {
0294: compoundAttrSetup();
0295:
0296: if (size < 1) {
0297: throw new IllegalArgumentException("Coumpound size = 0");
0298: }
0299: if (compoundSize() == 0) {
0300: persistentObjects = new PersistentObject[size];
0301: if (selfReferencing()) {
0302: selfReference();
0303: }
0304: } else if (compoundSize() < size) {
0305: PersistentObject[] newObjects = new PersistentObject[size];
0306: System.arraycopy(persistentObjects, 0, newObjects, 0,
0307: compoundSize());
0308: persistentObjects = newObjects;
0309: } else {
0310: // Case compoundSize() == size: do nothing
0311: }
0312: }
0313:
0314: /**
0315: * Returns next entry index to be used. This method will resize number of entries if necessary.
0316: *
0317: * @return next entry index to be used
0318: */
0319: protected int nextCompoundIndex() {
0320: int next = -1;
0321: if (persistentObjects != null) {
0322: int i = 0;
0323: for (; i < persistentObjects.length; i++) {
0324: if (persistentObjects[i] == null) {
0325: next = i;
0326: break;
0327: }
0328: }
0329: if (i == persistentObjects.length) {
0330: // resize:
0331: next = i;
0332: compound(i + 1);
0333: }
0334:
0335: } else {
0336: if (selfReferencing()) {
0337: compound(2);
0338: next = 1;
0339: }
0340: }
0341: return next;
0342: }
0343:
0344: /**
0345: * Sets extra coumpound attributes
0346: */
0347: protected void compoundAttrSetup() {
0348: unuseStarAndColumnNames();
0349: }
0350:
0351: /**
0352: * Returns number of compound etries
0353: *
0354: * @return number of compound etries
0355: */
0356: public int compoundSize() {
0357: return persistentObjects == null ? 0 : persistentObjects.length;
0358: }
0359:
0360: /**
0361: * Returns true if this is this type of object can be the 1st object of PersistentObject[]
0362: * of compound PersistentObject.
0363: *
0364: * @return true if this is the 1st object in PersistentObject[] of compound PersistentObject
0365: */
0366: public abstract boolean selfReferencing();
0367:
0368: protected Join addJoin() {
0369: if (_join == null) {
0370: _join = new JoinImpl(persistentObjects[0].record()
0371: .getTableName());
0372: }
0373: return _join;
0374: }
0375:
0376: public Compound.ImplicitJoinMode implicitJoinMode() {
0377: return _implicitJoinMode;
0378: }
0379:
0380: /**
0381: * Sets implicitJoinMode
0382: *
0383: * @param implicitJoinMode
0384: */
0385: public void implicitJoinMode(
0386: Compound.ImplicitJoinMode implicitJoinMode) {
0387: this ._implicitJoinMode = implicitJoinMode;
0388: }
0389:
0390: /**
0391: * Joins all the compound entries according to Compound.ImplicitJoinMode set
0392: *
0393: * @return new Join
0394: */
0395: public Join join() {
0396: if (_join == null) {
0397: return joinImplicitely(implicitJoinMode());
0398: } else {
0399: return _join;
0400: }
0401: }
0402:
0403: /**
0404: * Joins all the compound entries according to Compound.ImplicitJoinMode passed
0405: *
0406: * @param implicitJoinMode
0407: * @return new Join
0408: */
0409: public Join join(Compound.ImplicitJoinMode implicitJoinMode) {
0410: implicitJoinMode(implicitJoinMode);
0411: if (_join == null) {
0412: return joinImplicitely(implicitJoinMode());
0413: } else {
0414: return _join;
0415: }
0416: }
0417:
0418: public Join joinMinusOne() {
0419: if (_join == null) {
0420: return null;
0421: } else {
0422: return _join.joinMinusOne();
0423: }
0424: }
0425:
0426: public Join joinImplicitely(
0427: Compound.ImplicitJoinMode implicitJoinMode) {
0428: implicitJoinMode(implicitJoinMode);
0429: if (implicitJoinMode() == Compound.INNER) {
0430: joinImplicitely(false);
0431: } else if (implicitJoinMode() == Compound.OUTER) {
0432: joinImplicitely(true);
0433: } else if (implicitJoinMode() == Compound.NONE
0434: || implicitJoinMode() == null) {
0435: // Do nothing
0436: } else {
0437: throw new IllegalArgumentException("Unsupported mode "
0438: + implicitJoinMode());
0439: }
0440:
0441: return _join;
0442: }
0443:
0444: private Join joinImplicitely(boolean allOuter) {
0445: Join.Type[] joinTypes = new Join.Type[persistentObjects.length];
0446: for (int i = 0; i < joinTypes.length; i++) {
0447: joinTypes[i] = allOuter ? Join.LEFT : Join.INNER;
0448: }
0449: joinImplicitely(joinTypes);
0450: return _join;
0451: }
0452:
0453: /**
0454: * This method will create join implicitely based on the mutual references
0455: * To run it all the persistentObjects have to exist.
0456: */
0457: public Join joinImplicitely(Join.Type[] joinTypes) {
0458: if (joinTypes == null) {
0459: throw new IllegalArgumentException("joinTypes == null");
0460: }
0461: if (joinTypes.length != compoundSize()) {
0462: throw new IllegalArgumentException("joinTypes.length "
0463: + joinTypes.length + " != compoundSize"
0464: + compoundSize());
0465: }
0466:
0467: if (persistentObjects == null || persistentObjects.length == 0) {
0468: throw new IllegalArgumentException(
0469: "persistentObjects == null || persistentObjects.length == 0");
0470: } else if (persistentObjects[0] == null) {
0471: throw new IllegalArgumentException(
0472: "persistentObjects[0] == null");
0473: }
0474:
0475: _join = new JoinImpl(persistentObjects[0].record()
0476: .getTableName());
0477: for (int m = 1; m < persistentObjects.length; m++) {
0478: MetaTable masterTable = persistentObjects[m - 1].record()
0479: .getTable();
0480: String masterTableName = masterTable.getTableName();
0481: for (int i = 1; i < persistentObjects.length; i++) {
0482: //
0483: // Let's find the relationship to the next table:
0484: //
0485: if (persistentObjects[i] != null) {
0486: MetaTable slaveTable = persistentObjects[i]
0487: .record().getTable();
0488: String slaveTableName = slaveTable.getTableName();
0489: ForeignKeys slaveFkeys = slaveTable
0490: .getForeignKeys();
0491: addOneJoin(slaveFkeys, masterTableName,
0492: slaveTableName, joinTypes, i, false);
0493:
0494: ForeignKeys masterFkeys = masterTable
0495: .getForeignKeys();
0496: addOneJoin(masterFkeys, slaveTableName,
0497: masterTableName, joinTypes, i, true);
0498: }
0499: }
0500: }
0501: return _join;
0502: }
0503:
0504: private void addOneJoin(ForeignKeys slaveFkeys,
0505: String masterTableName, String slaveTableName,
0506: Join.Type[] joinTypes, int i, boolean inverse) {
0507: for (Iterator iterator = slaveFkeys.entrySet().iterator(); iterator
0508: .hasNext();) {
0509: Map.Entry entry = (Map.Entry) iterator.next();
0510: String foreignTableName = (String) entry.getKey();
0511: if (masterTableName.equals(foreignTableName)) {
0512: //
0513: // Found the link:
0514: //
0515: ForeignKeyEntries foregnKeyEntries = (ForeignKeyEntries) entry
0516: .getValue();
0517: List masterColumnNames = new ArrayList(foregnKeyEntries
0518: .size());
0519: List slaveColumnNames = new ArrayList(foregnKeyEntries
0520: .size());
0521: for (Iterator it = foregnKeyEntries.iterator(); it
0522: .hasNext();) {
0523: ForeignKeyEntry foreignKeyEntry = (ForeignKeyEntry) it
0524: .next();
0525: String fullMaster = new StringBuffer().append(
0526: masterTableName).append(".").append(
0527: foreignKeyEntry.getForeignColumn())
0528: .toString();
0529: String fullSlave = new StringBuffer().append(
0530: slaveTableName).append(".").append(
0531: foreignKeyEntry.getLocalColumn())
0532: .toString();
0533: masterColumnNames.add(fullMaster);
0534: slaveColumnNames.add(fullSlave);
0535: }
0536: String[] masterNames = (String[]) masterColumnNames
0537: .toArray(new String[masterColumnNames.size()]);
0538: String[] slaveNames = (String[]) slaveColumnNames
0539: .toArray(new String[slaveColumnNames.size()]);
0540: if (inverse) {
0541: _join.addJoin(joinTypes[i], masterTableName,
0542: masterNames, slaveNames);
0543: } else {
0544: _join.addJoin(joinTypes[i], slaveTableName,
0545: masterNames, slaveNames);
0546: }
0547: }
0548: }
0549: }
0550:
0551: /**
0552: * Sets <tt>PersistentObject</tt> - compound entry at specific index
0553: *
0554: * @param index index which entry to be set
0555: * @param persistentObject compound entry
0556: */
0557: public void compoundEntry(int index,
0558: PersistentObject persistentObject) {
0559: if (!compound()) {
0560: throw new IllegalArgumentException(
0561: "Attempt to call compoundEntry on non compound object");
0562: } else if (persistentObjects == null || compoundSize() == 0) {
0563: throw new RuntimeException(
0564: "<<BUG>>: persistentObjects == null || compoundSize() == 0 ");
0565: }
0566: if (persistentObject == null) {
0567: throw new IllegalArgumentException(
0568: "Attempt to set null in compoundEntry");
0569: }
0570: if (selfReferencing()) {
0571: if (index > compoundSize() - 1) {
0572: throw new IndexOutOfBoundsException(
0573: "Attempt to use index " + index
0574: + " while compoundSize = "
0575: + compoundSize());
0576: } else if (index < 1) {
0577: throw new IllegalArgumentException(
0578: "Cannot set index 0 since it's reserved for the mother object");
0579: }
0580: }
0581: persistentObjects[index] = persistentObject;
0582: }
0583:
0584: /**
0585: * Returns <tt>PersistentObject</tt> - compound entry at specific index
0586: *
0587: * @param index index which entry to be returned
0588: * @return <tt>PersistentObject</tt> - compound entry
0589: * @throws IndexOutOfBoundsException if there is no entry at requested index
0590: */
0591: public PersistentObject compoundEntry(int index) {
0592: selfReference();
0593: return persistentObjects == null ? null
0594: : persistentObjects[index];
0595: }
0596:
0597: /**
0598: * Makes this object the 1st object in PersistentObject[] of compound PersistentObject
0599: */
0600: protected abstract void selfReference();
0601:
0602: /**
0603: * Returns <tt>PersistentObject []</tt> - compound entries of this object
0604: *
0605: * @return <tt>PersistentObject []</tt> - compound entries of this object
0606: */
0607: public PersistentObject[] compoundEntries() {
0608: selfReference();
0609: return persistentObjects;
0610: }
0611:
0612: /**
0613: * Populates all entries by join
0614: */
0615: public void populateCompoundEntries() {
0616: if (persistentObjects != null) {
0617: for (int m = 1; m < compoundSize(); m++) {
0618: populateCompoundEntries(m);
0619: }
0620: }
0621: }
0622:
0623: /**
0624: * Populates all entries by join
0625: *
0626: * @param slaveIdx - index of the compound entry to populate
0627: */
0628: public void populateCompoundEntries(int slaveIdx) {
0629: if (persistentObjects != null
0630: && persistentObjects[slaveIdx].compoundCascadeInsert()) {
0631: MetaTable slaveTable = persistentObjects[slaveIdx].record()
0632: .getTable();
0633: ForeignKeys slaveFkeys = slaveTable.getForeignKeys();
0634:
0635: for (int i = 0; i < compoundSize(); i++) {
0636: MetaTable masterTable = persistentObjects[i].record()
0637: .getTable();
0638: String masterTableName = masterTable.getTableName();
0639: if (persistentObjects[i] != null) {
0640: for (Iterator iterator = slaveFkeys.entrySet()
0641: .iterator(); iterator.hasNext();) {
0642: Map.Entry entry = (Map.Entry) iterator.next();
0643: String foreignTableName = (String) entry
0644: .getKey();
0645: if (masterTableName.equals(foreignTableName)) {
0646: populateCompoundEntryByJoin(i, slaveIdx);
0647: }
0648: }
0649: }
0650: }
0651: }
0652: }
0653:
0654: /**
0655: * Populate compound Entry By Join
0656: *
0657: * @param indexFrom - persistentObjects index of the master object
0658: * @param indexTo - persistentObjects index of the slave object
0659: */
0660: public void populateCompoundEntryByJoin(int indexFrom, int indexTo) {
0661: if (_join == null) {
0662: return;
0663: }
0664: PersistentObject poFrom = persistentObjects[indexFrom];
0665: MetaTable metaTableFrom = persistentObjects[indexFrom].record()
0666: .getTable();
0667: PersistentObject poTo = persistentObjects[indexTo];
0668: MetaTable metaTableTo = persistentObjects[indexTo].record()
0669: .getTable();
0670:
0671: Join.Table tableTo = null;
0672: Join.Table tableFrom = null;
0673: int i = 0;
0674: for (Join.TableIterator it = _join.iterator(); it.hasNext(); i++) {
0675: Join.Table table = it.next();
0676: if (i == indexFrom) {
0677: tableFrom = table;
0678: }
0679:
0680: if (i == indexTo) {
0681: tableTo = table;
0682: }
0683: }
0684:
0685: if (tableTo == null) {
0686: throw new IllegalArgumentException(
0687: "Cannot find tableTo by index " + indexTo);
0688: }
0689:
0690: // Now chose which table ontains correct relationship:
0691: Join.Table tableRel = resolveTableRel(tableTo, metaTableTo,
0692: tableFrom, metaTableFrom);
0693:
0694: if (tableRel == null) {
0695: throw new IllegalArgumentException(
0696: "Cannot find tableRel by index " + indexTo);
0697: }
0698:
0699: for (i = 0; i < tableTo.getFirstTableColumns().length; i++) {
0700: String fromFullName = tableRel.getFirstTableColumns()[i];
0701: String toFullName = tableRel.getJoinedTableColumns()[i];
0702: ColumnStruct structFrom = parseFullName(fromFullName);
0703: ColumnStruct structTo = parseFullName(toFullName);
0704: if (structFrom.tableName != null
0705: && !structFrom.tableName.equals(metaTableFrom
0706: .getTableName())) {
0707: throw new IllegalArgumentException(
0708: "'From' Table name from join "
0709: + structFrom.tableName
0710: + " does not match that from object "
0711: + metaTableFrom.getTableName());
0712: }
0713:
0714: if (structTo.tableName != null
0715: && !structTo.tableName.equals(metaTableTo
0716: .getTableName())) {
0717: throw new IllegalArgumentException(
0718: "'To' Table name from join "
0719: + structTo.tableName
0720: + " does not match that from object "
0721: + metaTableTo.getTableName());
0722: }
0723:
0724: if (poTo.record().getObject(structTo.columnName) == null) {
0725: poTo.record().setObject(
0726: structTo.columnName,
0727: poFrom.record()
0728: .getObject(structFrom.columnName));
0729: }
0730: }
0731: poTo.toBeanFields();
0732: }
0733:
0734: private Join.Table resolveTableRel(Join.Table tableTo,
0735: MetaTable metaTableTo, Join.Table tableFrom,
0736: MetaTable metaTableFrom) {
0737: Join.Table tableRel = null;
0738: ColumnStruct structFrom;
0739: ColumnStruct structTo;
0740: if (tableTo.getFirstTableColumns()[0] != null
0741: && tableTo.getFirstTableColumns().length > 0) {
0742: structFrom = parseFullName(tableTo.getFirstTableColumns()[0]);
0743: structTo = parseFullName(tableTo.getJoinedTableColumns()[0]);
0744: if (structFrom.tableName.equals(metaTableFrom
0745: .getTableName())
0746: && structTo.tableName.equals(metaTableTo
0747: .getTableName())) {
0748: tableRel = tableTo;
0749: }
0750: }
0751:
0752: if (tableRel == null
0753: && tableFrom.getFirstTableColumns()[0] != null
0754: && tableFrom.getFirstTableColumns().length > 0) {
0755: structFrom = parseFullName(tableFrom.getFirstTableColumns()[0]);
0756: structTo = parseFullName(tableFrom.getJoinedTableColumns()[0]);
0757: if (structFrom.tableName.equals(metaTableFrom
0758: .getTableName())
0759: && structTo.tableName.equals(metaTableTo
0760: .getTableName())) {
0761: tableRel = tableFrom;
0762: }
0763:
0764: }
0765:
0766: if (tableRel == null) {
0767: throw new OdalRuntimePersistencyException(
0768: "Cannot resolve Table Rel for tables " + "from: "
0769: + metaTableTo.getTableName() + "to: "
0770: + metaTableTo.getTableName());
0771: }
0772:
0773: return tableRel;
0774: }
0775:
0776: private static ColumnStruct parseFullName(String fullName) {
0777: int firstIndex;
0778: int lastIndex;
0779: ColumnStruct struct = new ColumnStruct();
0780: if ((firstIndex = fullName.indexOf('.')) > 0) {
0781: lastIndex = fullName.lastIndexOf('.');
0782: if (firstIndex == lastIndex) {
0783: // pattern : tableName.columnName
0784: struct.tableName = fullName.substring(0, firstIndex);
0785: struct.columnName = fullName.substring(firstIndex + 1);
0786: } else {
0787: // pattern : schema.tableName.columnName
0788: struct.schema = fullName.substring(0, firstIndex);
0789: struct.tableName = fullName.substring(firstIndex + 1,
0790: lastIndex);
0791: struct.columnName = fullName.substring(lastIndex + 1);
0792: }
0793: } else {
0794: // pattern : columnName:
0795: struct.columnName = fullName;
0796: }
0797: return struct;
0798: }
0799:
0800: //
0801: // Compound end
0802: //
0803:
0804: /**
0805: * Sets query hint to use star in select clauses and names of PersistentObject columns when
0806: * retrieving from ResultSet. It should be used carefully since if there are repetitive SQL
0807: * names it can cause incorrect results
0808: */
0809: public void useStarAndColumnNames() {
0810: useSelectStar = true;
0811: useColumnNames = true;
0812: }
0813:
0814: /**
0815: * Unsets query hint to use star in select clauses and names of PersistentObject columns when
0816: * retrieving from ResultSet. It should be used carefully since if there are repetitive SQL
0817: * names it can cause incorrect results
0818: */
0819: public void unuseStarAndColumnNames() {
0820: useSelectStar = false;
0821: useColumnNames = false;
0822: }
0823:
0824: /**
0825: * Returns true query hint is set to use names of PersistentObject columns when
0826: * retrieving from ResultSet.
0827: *
0828: * @return true query hint is set to use names of PersistentObject columns when
0829: * retrieving from ResultSet.
0830: */
0831: public boolean usingColumnNames() {
0832: return useColumnNames;
0833: }
0834:
0835: /**
0836: * Returns true query hint is set to use star in select clauses.
0837: *
0838: * @return true query hint is set to use star in select clauses.
0839: */
0840: public boolean usingSelectStar() {
0841: return useSelectStar;
0842: }
0843:
0844: /**
0845: * Performs setup of compound object. Joins persistent entries if needed.
0846: */
0847: protected final void setupCompound() {
0848: //
0849: doSetupCompound();
0850: //
0851: join(Compound.INNER);
0852: }
0853:
0854: /**
0855: * Method to be overrriden in descendants and being called from setupCompound()
0856: */
0857: protected void doSetupCompound() {
0858: }
0859:
0860: /**
0861: * Unmarks this object as "InitializedComplex". Also resets LinkDependencyGraph.
0862: */
0863: public void unmarkInitializedComplex() {
0864: }
0865:
0866: protected abstract void flatten0();
0867:
0868: /**
0869: * Flattens this <tt>PersistentObject</tt>. Flattening is procedure of making
0870: * <tt>PersistentObject</tt> a simple POJO like. All the additional
0871: * structures used to keep records and links are nullified. The values are though preserved
0872: * in the object fields.
0873: *
0874: * @return itself
0875: */
0876: public final AbstractPersistentObject flatten() {
0877: if (persistentObjects != null) {
0878: for (int i = 0; i < persistentObjects.length; i++) {
0879: if (persistentObjects[i] != null) {
0880: persistentObjects[i].flatten0();
0881: }
0882: }
0883: } else {
0884: flatten0();
0885: }
0886: return this ;
0887: }
0888:
0889: protected abstract void unflatten0();
0890:
0891: /**
0892: * Unflattening is procedure opposite to flattening.
0893: *
0894: * @return itself
0895: * @see com.completex.objective.components.persistency.AbstractPersistentObject#flatten()
0896: */
0897: public final AbstractPersistentObject unflatten() {
0898: AbstractPersistentObject persistent = this
0899: .newPersistentInstance();
0900: if (persistentObjects != null) {
0901: for (int i = 0; i < persistent.persistentObjects.length; i++) {
0902: if (persistent.persistentObjects[i] != null) {
0903: persistentObjects[i]
0904: .record(persistent.persistentObjects[i]
0905: .record());
0906: persistentObjects[i].unflatten0();
0907: }
0908: }
0909: } else if (persistent instanceof PersistentObject) {
0910: ((PersistentObject) this )
0911: .record(((PersistentObject) persistent).record());
0912: unflatten0();
0913: }
0914: return this ;
0915: }
0916:
0917: public boolean equals(Object obj) {
0918: return equalsCompound(obj);
0919: }
0920:
0921: /**
0922: * Equals by Basic Peristent Object fields (without children objects)
0923: *
0924: * @param value the reference object with which to compare
0925: * @return true if basic persistent object fields are equal
0926: */
0927: public boolean equalsBasic(Object value) {
0928: return (this == value);
0929: }
0930:
0931: /**
0932: * Equals by Coumpound Peristent Object entries (without children objects)
0933: *
0934: * @param value the reference object with which to compare
0935: * @return true if Coumpound Peristent Object entries are equal
0936: */
0937: public boolean equalsCompound(Object value) {
0938: if (value == null || this .getClass() != value.getClass()) {
0939: return false;
0940: }
0941: if (compound() != ((PersistentObject) value).compound()) {
0942: return false;
0943: }
0944: if (compound()) {
0945: PersistentObject[] thatEntries = ((PersistentObject) value)
0946: .compoundEntries();
0947: for (int i = 0; i < persistentObjects.length; i++) {
0948: PersistentObject this Entry = persistentObjects[i];
0949: PersistentObject thatEntry = thatEntries[i];
0950: if (this Entry != null ? !this Entry
0951: .equalsBasic(thatEntry) : thatEntry != null) {
0952: return false;
0953: }
0954: }
0955: return true;
0956: } else {
0957: return equalsBasic(value);
0958: }
0959: }
0960:
0961: public boolean fromCache() {
0962: return fromCache;
0963: }
0964:
0965: public void markFromCache(boolean fromCache) {
0966: this .fromCache = fromCache;
0967: }
0968:
0969: /**
0970: *
0971: * @return internal type
0972: */
0973: public String mappingType() {
0974: return mappingType;
0975: }
0976:
0977: /**
0978: * Sets internal type
0979: *
0980: * @param mappingType
0981: */
0982: public void mappingType(String mappingType) {
0983: this .mappingType = mappingType;
0984: }
0985:
0986: /**
0987: * Returns hash code by basic persistent object fields
0988: *
0989: * @return hash code by basic persistent object fields are equal
0990: */
0991: public int hashCodeBasic() {
0992: return 0;
0993: }
0994:
0995: public static boolean isEmptyEntry(PersistentObject entry) {
0996: if (entry == null) {
0997: return true;
0998: }
0999:
1000: PersistentObject po = entry;
1001: if (entry.flattened()) {
1002: try {
1003: po = (PersistentObject) entry.clone();
1004: } catch (Exception e) {
1005: throw new OdalRuntimePersistencyException(
1006: "isNullEntry failed " + e.getMessage());
1007: }
1008: po.unflatten();
1009: }
1010: List primaryKey = po.record().getPrimaryKey();
1011: if (primaryKey != null && !primaryKey.isEmpty()) {
1012: for (int i = 0; i < primaryKey.size(); i++) {
1013: Number index = (Number) primaryKey.get(i);
1014: Object value = po.record().getObject(index.intValue());
1015: if (value == null) {
1016: return true;
1017: }
1018: }
1019: return false;
1020: } else {
1021: for (int i = 0; i < po.record().getTable().size(); i++) {
1022: Object value = po.record().getObject(i);
1023: if (value != null) {
1024: return false;
1025: }
1026: }
1027: return true;
1028: }
1029: }
1030:
1031: private static class ColumnStruct {
1032: String schema;
1033: String tableName;
1034: String columnName;
1035:
1036: public String toString() {
1037: return "schema = " + schema + "; tableName = " + tableName
1038: + "; columnName = " + columnName;
1039: }
1040: }
1041:
1042: public static void main(String[] args) {
1043: String[] strings = new String[] { "schema.table.column",
1044: "table.column", "column", };
1045:
1046: for (int i = 0; i < strings.length; i++) {
1047: System.out.println(parseFullName(strings[i]));
1048: }
1049: }
1050:
1051: }
|