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.impl.LinkDependencyGraph;
0012: import com.completex.objective.components.persistency.core.impl.LinkIterator;
0013: import com.completex.objective.components.persistency.core.impl.query.NonCompilingQueryFactory;
0014: import com.completex.objective.components.persistency.type.TracingCollection;
0015: import com.completex.objective.components.OdalRuntimeException;
0016:
0017: import java.io.IOException;
0018: import java.io.ObjectInput;
0019: import java.io.ObjectOutput;
0020: import java.sql.SQLException;
0021: import java.util.Collection;
0022: import java.util.Date;
0023: import java.util.HashMap;
0024: import java.util.Iterator;
0025: import java.util.List;
0026: import java.util.Map;
0027: import java.util.Set;
0028:
0029: /**
0030: * Ancestor of all generated persistent objects. Its descendants can be used as return type
0031: * as well as in "queries by example". If no "singular result factory" is specified for Query or Call,
0032: * the retrieved records will be placed into raw PersistentObject instances. In this case
0033: * field values can be accessed through its Record by calling:
0034: * <p/>
0035: * <PRE>
0036: * persistentObject.record().getXXX();
0037: * </PRE>
0038: * methods.
0039: *
0040: * @author Gennady Krizhevsky
0041: * @see Record
0042: */
0043: public class PersistentObject extends AbstractPersistentObject
0044: implements Compound {
0045:
0046: public static final StringBuffer NULL_BUFFER = new StringBuffer();
0047:
0048: private transient boolean _preinitializedComplex;
0049: private transient boolean _initializedComplex;
0050: private transient Record _record;
0051: private transient Boolean _trace;
0052:
0053: //
0054: // Links for the master (template) object - only for complex objects
0055: //
0056: private transient Link[] _links;
0057:
0058: //
0059: // This is a template object:
0060: //
0061: private transient PersistentObject _master;
0062:
0063: public PersistentObject() {
0064: postInitializeRecord();
0065: }
0066:
0067: public PersistentObject(Record record) {
0068: validate(record);
0069: this ._record = record;
0070: if (record != null) {
0071: this ._record.setPersistentObject(this );
0072: }
0073:
0074: postInitializeRecord();
0075:
0076: if (complex() && !_preinitializedComplex
0077: && !_initializedComplex) {
0078: preinitializeComplex();
0079: }
0080:
0081: if (compound()) {
0082: compoundAttrSetup();
0083: setupCompound();
0084: }
0085: }
0086:
0087: /**
0088: * Returns links that define children of this PersistentObject
0089: *
0090: * @param queryFactory
0091: * @return Link[] - links that define children of this PersistentObject
0092: */
0093: public Link[] retrieveLinks(QueryFactory queryFactory) {
0094: if (this ._links == null) {
0095: this ._links = links(queryFactory);
0096: }
0097: return this ._links;
0098: }
0099:
0100: //
0101: // Compound begin:
0102: //
0103:
0104: /**
0105: * Sets this object as compound.
0106: *
0107: * @param compound
0108: */
0109: protected void compound(boolean compound) {
0110: compound(1);
0111: }
0112:
0113: /**
0114: * Returns true.
0115: *
0116: * @return true
0117: * @see AbstractPersistentObject#selfReferencing()
0118: */
0119: public boolean selfReferencing() {
0120: return true;
0121: }
0122:
0123: /**
0124: * Makes this object the 1st object in PersistentObject[] of compound PersistentObject
0125: */
0126: protected void selfReference() {
0127: if (persistentObjects != null && persistentObjects.length > 0) {
0128: persistentObjects[0] = this ;
0129: }
0130: }
0131:
0132: //
0133: // Compound end.
0134: //
0135:
0136: /**
0137: * Preinitializes complex <tt>PersistentObject</tt>. Creates master <tt>PersistentObject</tt>
0138: * of this class and assembles it populating its <tt>LinkDependencyGraph</tt>.
0139: * The master is used down the road as a template object to assemble new instances of this class.
0140: * Creating and assembling of the master is done once for every
0141: * specific <tt>Persistency</tt> instance it is used with.
0142: * Does nothing if the object is not complex.
0143: *
0144: * @return itself
0145: */
0146: protected PersistentObject preinitializeComplex() {
0147: // System.out.println("Enter PersistentObject::preinitialize: " + getClass());
0148: if (!complex() || _preinitializedComplex) {
0149: return this ;
0150: }
0151:
0152: QueryFactory queryFactory = NonCompilingQueryFactory
0153: .getInstance();
0154:
0155: PersistentObject master = null;
0156: instantiateRegisteredMasters();
0157: if (!classInitialized(queryFactory)) {
0158: synchronized (classLock()) {
0159: if (!classInitialized(queryFactory)) {
0160: String key = registrationKey(queryFactory);
0161: registerMaster(key);
0162: master = master(queryFactory);
0163: registerDependent(queryFactory, master);
0164: master.record().setDependencyGraph(
0165: new LinkDependencyGraph(master));
0166: this ._master = master;
0167: }
0168: }
0169: } else {
0170: master = master(queryFactory);
0171: this ._master = master;
0172: }
0173:
0174: synchronized (this ) {
0175: if (!_preinitializedComplex) {
0176: newPersistentObjectPreSetup(this , master);
0177: _preinitializedComplex = true;
0178: }
0179: }
0180: return this ;
0181: }
0182:
0183: /**
0184: * Initializes complex <tt>PersistentObject</tt>. Uses the master object
0185: * as a template to assemble new instance.
0186: * Does nothing if the object is not complex.
0187: *
0188: * @param queryFactory
0189: * @return itself
0190: */
0191: public PersistentObject initializeComplex(QueryFactory queryFactory) {
0192: if (!complex() || _initializedComplex) {
0193: return this ;
0194: }
0195:
0196: PersistentObject master;
0197: if (_preinitializedComplex) {
0198: master = master(NonCompilingQueryFactory.getInstance());
0199: if (master == null) {
0200: throw new IllegalArgumentException(
0201: "Cannot find preinitialized master for " + this );
0202: }
0203: } else {
0204: throw new IllegalArgumentException(
0205: "Cannot initialize class that not preinitialized master: "
0206: + this );
0207: }
0208:
0209: if (!classInitialized(queryFactory)) {
0210: synchronized (classLock()) {
0211: if (!classInitialized(queryFactory)) {
0212: LinkDependencyGraph masterDependencyGraph = master
0213: .record().getDependencyGraph();
0214: if (masterDependencyGraph != null
0215: && masterDependencyGraph.hasMetaAssembly()) {
0216: for (int i = 0; i < masterDependencyGraph
0217: .metaAssemblySize(); i++) {
0218: Link link = masterDependencyGraph
0219: .getMetaAssemblyLink(i);
0220: if (link.getQuery() != null) {
0221: link.getQuery().decompile();
0222: ((QueryCtl) link.getQuery())
0223: .setParentQueryFactory(queryFactory);
0224: }
0225: }
0226: }
0227: reregisterMaster(
0228: registrationKey(NonCompilingQueryFactory
0229: .getInstance()),
0230: registrationKey(queryFactory));
0231: }
0232: }
0233: }
0234:
0235: if (!_initializedComplex) {
0236: synchronized (this ) {
0237: if (!_initializedComplex) {
0238: LinkDependencyGraph linkDependencyGraph;
0239: try {
0240: linkDependencyGraph = (LinkDependencyGraph) master
0241: .record().getDependencyGraph().clone();
0242: } catch (CloneNotSupportedException e) {
0243: throw new RuntimeException(e);
0244: }
0245: newPersistentObjectSetup(this , master);
0246: this .record().setDependencyGraph(
0247: linkDependencyGraph);
0248:
0249: // Now we go by path and replace values in final assembly:
0250: Link parent = toLink();
0251: String path = Link.ROOT;
0252: linkDependencyGraph.addToAssembly(path, parent);
0253: addToAssembly(path, parent, linkDependencyGraph,
0254: queryFactory);
0255: _initializedComplex = true;
0256: }
0257: }
0258: }
0259:
0260: return this ;
0261: }
0262:
0263: /**
0264: * Returns master (template) object assuming it was already set for this instance
0265: * which is done in preinitializeComplex() method
0266: *
0267: * @return master object
0268: */
0269: protected PersistentObject master() {
0270: return _master;
0271: }
0272:
0273: /**
0274: * Registers this object as a master.
0275: *
0276: * @param registrationKey
0277: */
0278: protected void registerMaster(String registrationKey) {
0279: PersistentObject persistent = (PersistentObject) this .clone();
0280: registeredMasters().put(registrationKey, persistent);
0281:
0282: }
0283:
0284: /**
0285: * Instantiates Registered Masters (Map) in thread safe manner.
0286: * Has to be overridden by descendants.
0287: *
0288: * @throws UnsupportedOperationException if it is not overridden by descendant
0289: */
0290: protected void instantiateRegisteredMasters() {
0291: throw new UnsupportedOperationException();
0292: }
0293:
0294: /**
0295: * To traverse the graph follow the pattern:
0296: * <PRE>
0297: * record.toLink
0298: * |-> result
0299: * |-> record.toLink / collection -> record.toLink
0300: * |-> children <-| (meta-data)
0301: * </PRE>
0302: *
0303: * @param path link path
0304: * @param parent parent link
0305: * @param linkDependencyGraph LinkDependencyGraph
0306: * @param queryFactory QueryFactory
0307: */
0308: protected void addToAssembly(String path, Link parent,
0309: LinkDependencyGraph linkDependencyGraph,
0310: QueryFactory queryFactory) {
0311: if (parent.hasChildren()) {
0312: for (LinkIterator it = parent.linkIterator(); it.hasNext();) {
0313: Link link = it.nextLink();
0314: if (!link.isAdHoc()) {
0315: String linkPath = path + Link.SEP + link.getName();
0316: Object result = link.getResult();
0317: if (result != null) {
0318: if (result instanceof PersistentObject) {
0319: PersistentObject persistentObject = (PersistentObject) result;
0320: addToAssemblyOne(persistentObject, parent,
0321: linkDependencyGraph, linkPath,
0322: queryFactory);
0323: } else if (result instanceof Collection) {
0324: for (Iterator iterator = ((Collection) result)
0325: .iterator(); iterator.hasNext();) {
0326: PersistentObject persistentObject = (PersistentObject) iterator
0327: .next();
0328: addToAssemblyOne(persistentObject,
0329: parent, linkDependencyGraph,
0330: linkPath, queryFactory);
0331: }
0332: } else {
0333: throw new UnsupportedOperationException(
0334: "Unsupported type: " + result);
0335: }
0336: }
0337: }
0338: }
0339: }
0340: }
0341:
0342: private void addToAssemblyOne(PersistentObject persistentObject,
0343: Link parent, LinkDependencyGraph linkDependencyGraph,
0344: String linkPath, QueryFactory queryFactory) {
0345: persistentObject.toLink().setParentLink(parent);
0346: linkDependencyGraph.addToAssembly(linkPath, persistentObject
0347: .toLink());
0348: addToAssembly(linkPath, persistentObject.toLink(),
0349: linkDependencyGraph, queryFactory);
0350: }
0351:
0352: /**
0353: * Return true if class is initialized.
0354: *
0355: * @param queryFactory QueryFactory
0356: * @return true if class is initialized
0357: */
0358: protected boolean classInitialized(QueryFactory queryFactory) {
0359: if (!complex()) {
0360: return false;
0361: }
0362: return registeredMasters().containsKey(
0363: registrationKey(queryFactory));
0364: }
0365:
0366: /**
0367: * Re-registers master object under different registration key. Re-registration is done once per 1st
0368: * usage of object of this class with specific Persistency.
0369: *
0370: * @param oldRegistrationKey
0371: * @param newRegistrationKey
0372: */
0373: protected void reregisterMaster(String oldRegistrationKey,
0374: String newRegistrationKey) {
0375: PersistentObject master = (PersistentObject) registeredMasters()
0376: .get(oldRegistrationKey);
0377: registeredMasters().put(newRegistrationKey, master);
0378: }
0379:
0380: /**
0381: * Retrieves master object from the registry using QueryFactory to build registration key
0382: *
0383: * @param queryFactory QueryFactory
0384: * @return master PersistentObject
0385: */
0386: protected PersistentObject master(QueryFactory queryFactory) {
0387: return (PersistentObject) registeredMasters().get(
0388: registrationKey(this .getClass(), queryFactory));
0389: }
0390:
0391: /**
0392: * Return registeredMasters Map. Has to be overriden in descendants.
0393: *
0394: * @return registeredMasters Map
0395: * @throws UnsupportedOperationException if it is not overridden by descendant
0396: */
0397: protected Map registeredMasters() {
0398: throw new UnsupportedOperationException();
0399: }
0400:
0401: /**
0402: * Returns class lock for objects of this class
0403: *
0404: * @return class lock
0405: */
0406: protected Object classLock() {
0407: return this .getClass();
0408: }
0409:
0410: /**
0411: * Adds child links to the master object.
0412: *
0413: * @param queryFactory
0414: * @param master
0415: */
0416: protected void registerDependent(QueryFactory queryFactory,
0417: PersistentObject master) {
0418: Map circularCheckSet = new HashMap();
0419: Link[] links = master.retrieveLinks(queryFactory);
0420: Link parentLink = master.record().toLink();
0421: registerDependent(queryFactory, parentLink, links,
0422: circularCheckSet);
0423: }
0424:
0425: private void registerDependent(QueryFactory queryFactory,
0426: Link parentLink, Link[] links, Map circularCheckSet) {
0427: if (links != null) {
0428: for (int i = 0; i < links.length; i++) {
0429: Link linkToAdd = links[i];
0430: if (linkToAdd.getName() == null) {
0431: throw new IllegalArgumentException(
0432: "Link name is null");
0433: }
0434: //
0435: // Check if the link already there:
0436: //
0437: // Get class:
0438: Class parentClazz;
0439: PersistentObjectFactory parentFactory;
0440: if (parentLink.getQuery() != null
0441: && parentLink.getQuery()
0442: .getSingularResultFactory() != null) {
0443: parentFactory = parentLink.getQuery()
0444: .getSingularResultFactory();
0445: parentClazz = parentFactory.getClass();
0446: } else {
0447: parentFactory = this ;
0448: parentClazz = this .getClass();
0449: }
0450:
0451: Class childClazz;
0452: PersistentObjectFactory childFactory;
0453: if (linkToAdd.getQuery() != null
0454: && linkToAdd.getQuery()
0455: .getSingularResultFactory() != null) {
0456: childFactory = linkToAdd.getQuery()
0457: .getSingularResultFactory();
0458: childClazz = childFactory.getClass();
0459: } else {
0460: throw new IllegalArgumentException(
0461: "Link with no query or Singular result factory ");
0462: }
0463:
0464: String key;
0465: if ((key = circularDependencyKey(parentFactory,
0466: childFactory, linkToAdd)) == null) {
0467: key = circularDependencyKey(parentClazz,
0468: childClazz, linkToAdd);
0469: }
0470: if (circularCheckSet.containsKey(key)) {
0471: //
0472: // Circular dependency now is okay - do not propagate:
0473: //
0474: Link circularLink = (Link) circularCheckSet
0475: .get(key);
0476: circularLink.setEndOfChain(true);
0477: return;
0478: } else {
0479: circularCheckSet.put(key, linkToAdd);
0480: }
0481:
0482: parentLink.addChild(linkToAdd);
0483:
0484: if (linkToAdd.getQuery() != null
0485: && linkToAdd.getQuery()
0486: .getSingularResultFactory() != null) {
0487: PersistentObject temp = (PersistentObject) links[i]
0488: .getQuery().getSingularResultFactory();
0489: if (temp.complex()) {
0490: Link[] tempLinks = temp
0491: .retrieveLinks(queryFactory);
0492: if (tempLinks != null && tempLinks.length > 0) {
0493: registerDependent(queryFactory, linkToAdd,
0494: tempLinks, circularCheckSet);
0495: }
0496: }
0497: }
0498: }
0499: }
0500: }
0501:
0502: private String circularDependencyKey(Class parentClazz,
0503: Class childClazz, Link linkToAdd) {
0504: return parentClazz.getName() + Link.SEP + childClazz.getName()
0505: + Link.SEP + linkToAdd.getName();
0506: }
0507:
0508: private String circularDependencyKey(
0509: PersistentObjectFactory parentFactory,
0510: PersistentObjectFactory childFactory, Link linkToAdd) {
0511: if (parentFactory instanceof PersistentObject) {
0512: PersistentObject parent = (PersistentObject) parentFactory;
0513: if (parent.record() != null) {
0514: String parentTableName = parent.record().getTableName();
0515: String childTableName = ((PersistentObject) childFactory)
0516: .record().getTableName();
0517: return parentTableName + Link.SEP + childTableName
0518: + Link.SEP + linkToAdd.getName();
0519: } else {
0520: return null;
0521: }
0522: } else {
0523: return null;
0524: }
0525: }
0526:
0527: /**
0528: * Builds master object registration key based on class name and QueryFactory
0529: *
0530: * @param queryFactory
0531: * @return master object registration key
0532: */
0533: protected String registrationKey(QueryFactory queryFactory) {
0534: return registrationKey(this .getClass(), queryFactory);
0535: }
0536:
0537: /**
0538: * Builds master object registration key based on class name and QueryFactory
0539: *
0540: * @param clazz Class
0541: * @param queryFactory QueryFactory
0542: * @return master object registration key
0543: */
0544: static String registrationKey(Class clazz, QueryFactory queryFactory) {
0545: Persistency persistency = queryFactory.getPersistency();
0546: return new StringBuffer(clazz.getName()).append("|").append(
0547: persistency.getClass().getName()).append("@").append(
0548: Integer.toHexString(persistency.hashCode())).toString();
0549: }
0550:
0551: /**
0552: * Returns links that define children of this <tt>PersistentObject</tt>
0553: *
0554: * @param queryFactory
0555: * @return Link[] - links that define children of this <tt>PersistentObject</tt>
0556: */
0557: protected Link[] links(QueryFactory queryFactory) {
0558: return null;
0559: }
0560:
0561: /**
0562: * Returns <tt>Link</tt> reperesentation of this <tt>PersistentObject</tt>
0563: *
0564: * @return Link reperesentation of this Record
0565: */
0566: public Link toLink() {
0567: Link link = _record.toLink();
0568: link.setResult(this );
0569: return link;
0570: }
0571:
0572: private Record dependencyGraph() {
0573: if (_record.getDependencyGraph() == null) {
0574: LinkDependencyGraph dependencyGraph = new LinkDependencyGraph();
0575: _record.setDependencyGraph(dependencyGraph);
0576: }
0577: return _record;
0578: }
0579:
0580: /**
0581: * Assembles <tt>LinkDependencyGraph</tt> associated with this <tt>PersistentObject</tt>
0582: */
0583: public void assemble() {
0584: dependencyGraph().assemble(this );
0585: }
0586:
0587: private void validate(Record record) {
0588: if (record == null) {
0589: throw new IllegalArgumentException("Record may not be null");
0590: }
0591: }
0592:
0593: /**
0594: * Returns <tt>Record</tt> associated with this <tt>PersistentObject</tt>
0595: *
0596: * @return <tt>Record</tt> associated with this <tt>PersistentObject</tt>
0597: */
0598: public Record record() {
0599: return _record;
0600: }
0601:
0602: /**
0603: * Sets <tt>Record</tt> associated with this <tt>PersistentObject</tt>
0604: */
0605: protected void record(Record record) {
0606: validate(record);
0607: this ._record = record;
0608: this ._record.setPersistentObject(this );
0609: }
0610:
0611: /**
0612: * Returns <tt>Record</tt> associated with this <tt>PersistentObject</tt>
0613: *
0614: * @return <tt>Record</tt> associated with this <tt>PersistentObject</tt>
0615: * @throws OdalRuntimePersistencyException
0616: * if this object is flattened
0617: */
0618: public Record record2() {
0619: invalidateOnFlattened();
0620: return _record;
0621: }
0622:
0623: /**
0624: * Sets autoPadChars flag.
0625: * If set to true, character fields will be right padded with spaces to column length
0626: *
0627: * @param autoPadChars if true char fields will be right padded with spaces to column length
0628: */
0629: public void autoPadChars(boolean autoPadChars) {
0630: _record.setAutoPadChars(autoPadChars);
0631: }
0632:
0633: /**
0634: * Factory mathod
0635: *
0636: * @return new <tt>PersistentObject</tt>
0637: */
0638: public PersistentObject newPersistentObject() {
0639: try {
0640: PersistentObject persistentObject = (PersistentObject) this
0641: .getClass().newInstance();
0642: if (persistentObject.record() == null && _record != null) {
0643: persistentObject.record(_record.newRecord());
0644: persistentObject.toLink();
0645: }
0646: persistentObject._trace = _trace;
0647: persistentObject.postInitializeRecord();
0648: return persistentObject;
0649: } catch (Exception e) {
0650: throw new RuntimeException(
0651: "Cannot instantiate PersistentObject by class name ["
0652: + this .getClass().getName() + "]", e);
0653: }
0654: }
0655:
0656: /**
0657: * Performs pre-setup of "to" object based on properties of "from" object.
0658: * Namely, all results are copied from "from" to "to" excluding those of child objects.
0659: * Newly created "to" record is linked to "to" PersistentObject.
0660: *
0661: * @param to target <tt>PersistentObject</tt>
0662: * @param from <tt>PersistentObject</tt> used as a template
0663: */
0664: protected static void newPersistentObjectPreSetup(
0665: PersistentObject to, PersistentObject from) {
0666: if (from != null) {
0667: Record origRecord = to.record();
0668: Record fromRecord = from.record();
0669: to.record(fromRecord.newRecord());
0670: to.record().copyDirty(origRecord, null);
0671: to.record().setPersistentObject(to);
0672: Link toLink = to.toLink();
0673: Link origToLink = origRecord.toLink();
0674: toLink.copyResultsOneLevel(origToLink);
0675: }
0676: }
0677:
0678: /**
0679: * Performs setup of "to" object based on properties of "from" object.
0680: * Namely, links structure, served as meta-data, is copied from "from" <tt>PersistentObject</tt>
0681: * to "to" one.
0682: *
0683: * @param to target <tt>PersistentObject</tt>
0684: * @param from <tt>PersistentObject</tt> used as a template
0685: */
0686: protected static void newPersistentObjectSetup(PersistentObject to,
0687: PersistentObject from) {
0688: if (from != null) {
0689: Record origRecord = to.record();
0690: to.record(from.record().newRecord());
0691: Record.setupPrimitiveFields(origRecord, to.record());
0692: to.record().copyPreseveStates(origRecord);
0693: Link toLink = to.toLink();
0694: Link origToLink = origRecord.toLink();
0695: toLink.copyResults(origToLink);
0696: }
0697: }
0698:
0699: /**
0700: * Returns <tt>PersistentObjectFactory</tt> of this object
0701: *
0702: * @return <tt>PersistentObjectFactory</tt> of this object
0703: */
0704: protected PersistentObjectFactory factory() {
0705: return this ;
0706: }
0707:
0708: /**
0709: * @return new instance of this object preserving tracing mode
0710: * @see PersistentObject#traceOn()
0711: * @see PersistentObject#traceOff()
0712: */
0713: public AbstractPersistentObject newPersistentInstance() {
0714: return newPersistentObject();
0715: }
0716:
0717: /**
0718: * Returns deep copy of this object
0719: *
0720: * @return deep copy of this object
0721: */
0722: public Object clone() {
0723: PersistentObject persistentObject = (PersistentObject) super
0724: .clone();
0725: try {
0726: if (!flattened()) {
0727: persistentObject.record((Record) _record.clone());
0728: persistentObject._preinitializedComplex = false;
0729: persistentObject.toLink();
0730: persistentObject.toBeanFields();
0731: persistentObject.unmarkInitializedComplex();
0732: persistentObject._record
0733: .setPersistentObject(persistentObject);
0734: }
0735: return persistentObject;
0736: } catch (Exception e) {
0737: throw new OdalRuntimePersistencyException(
0738: "Cannot clone PersistentObject by class name ["
0739: + this .getClass().getName() + "]", e);
0740: }
0741: }
0742:
0743: /**
0744: * Copies updateable fields from source record to this record.
0745: * Only "dirty" fields are copied
0746: *
0747: * @param source source <tt>PersistentObject</tt>
0748: */
0749: public void copyDirty(PersistentObject source) {
0750: copyDirty(source, null);
0751: }
0752:
0753: /**
0754: * Copies updateable fields from source record to this record.
0755: * Only "dirty" fields are copied
0756: *
0757: * @param source source <tt>PersistentObject</tt>
0758: * @param updateableFields set of updateable column names
0759: */
0760: public void copyDirty(PersistentObject source, Set updateableFields) {
0761: copy(source, updateableFields, true);
0762: }
0763:
0764: /**
0765: * Copies updateable fields from source persistent object to this persistent object.
0766: * If the persistent objects are compound then all the entries will be copied.
0767: * If updateableFields Set is null then all dirty fields will be copied.
0768: * If dirtyFieldsOnly flag is true then only dirty fields are copied
0769: *
0770: * @param source source <tt>PersistentObject</tt>
0771: * @param updateableFields set of updateable column names
0772: * @param dirtyFieldsOnly if true only dirty fields are copied
0773: */
0774: public void copy(PersistentObject source, Set updateableFields,
0775: boolean dirtyFieldsOnly) {
0776: copy(source, updateableFields, dirtyFieldsOnly, false);
0777: }
0778:
0779: /**
0780: * Copies updateable fields from source persistent object to this persistent object.
0781: * If the persistent objects are compound then all the entries will be copied.
0782: * If updateableFields Set is null then all dirty fields will be copied.
0783: * If dirtyFieldsOnly flag is true then only dirty fields are copied
0784: *
0785: * @param source source <tt>PersistentObject</tt>
0786: * @param updateableFields set of updateable column names
0787: * @param dirtyFieldsOnly if true only dirty fields are copied
0788: * @param preserveStates if true target record "dirty" states are set the same as the source record fields "dirty" states
0789: * even if the values are the same
0790: */
0791: public void copy(PersistentObject source, Set updateableFields,
0792: boolean dirtyFieldsOnly, boolean preserveStates) {
0793: if (this .compound() && !source.compound() || !this .compound()
0794: && source.compound()) {
0795: throw new IllegalArgumentException(
0796: "Cannot copy since source and target objects "
0797: + "compound properties are different");
0798: } else if (this .compound() && source.compound()) {
0799: if (this .compoundSize() != source.compoundSize()) {
0800: throw new IllegalArgumentException(
0801: "Cannot copy since number of compound entries in source and target objects "
0802: + "is different");
0803: }
0804: }
0805:
0806: if (compound()) {
0807: PersistentObject[] this Entries = compoundEntries();
0808: for (int i = 0; i < this Entries.length; i++) {
0809: PersistentObject this Entry = this Entries[i];
0810: PersistentObject sourceEntry = source.compoundEntry(i);
0811: copyBasic(sourceEntry, this Entry, updateableFields,
0812: dirtyFieldsOnly, preserveStates);
0813: }
0814: } else {
0815: copyBasic(source, this , updateableFields, dirtyFieldsOnly,
0816: preserveStates);
0817: }
0818: }
0819:
0820: /**
0821: * Copies updateable fields from source basic persistent object to this basic persistent object.
0822: * If updateableFields Set is null then all dirty fields will be copied.
0823: * If dirtyFieldsOnly flag is true then only dirty fields are copied
0824: *
0825: * @param source source <tt>PersistentObject</tt>
0826: * @param updateableFields set of updateable column names
0827: * @param dirtyFieldsOnly if true only dirty fields are copied
0828: */
0829: public void copyBasic(PersistentObject source,
0830: Set updateableFields, boolean dirtyFieldsOnly) {
0831: copyBasic(source, this , updateableFields, dirtyFieldsOnly,
0832: false);
0833: }
0834:
0835: /**
0836: * Copies all fields from source basic persistent object to this basic persistent object.
0837: *
0838: * @param source source <tt>PersistentObject</tt>
0839: * from source record to this record even if the values are the same
0840: */
0841: public void copyBasic(PersistentObject source) {
0842: copyBasic(source, null, false);
0843: }
0844:
0845: /**
0846: * Copies updateable fields from source basic persistent object to this basic persistent object.
0847: * Only "dirty" fields are copied
0848: *
0849: * @param source source <tt>PersistentObject</tt>
0850: * @param updateableFields set of updateable column names
0851: */
0852: public void copyBasicDirty(PersistentObject source,
0853: Set updateableFields) {
0854: copyBasic(source, updateableFields, true);
0855: }
0856:
0857: /**
0858: * Copies updateable fields from source basic persistent object to this basic persistent object.
0859: * If updateableFields Set is null then all dirty fields will be copied.
0860: * If dirtyFieldsOnly flag is true then only dirty fields are copied
0861: *
0862: * @param source source <tt>PersistentObject</tt>
0863: * @param target target <tt>PersistentObject</tt>
0864: * @param updateableFields set of updateable column names
0865: * @param dirtyFieldsOnly if true only dirty fields are copied
0866: * @param preserveStates if true target record "dirty" states are set the same as the source record fields "dirty" states
0867: * even if the values are the same
0868: */
0869: public static void copyBasic(PersistentObject source,
0870: PersistentObject target, Set updateableFields,
0871: boolean dirtyFieldsOnly, boolean preserveStates) {
0872: if (source == null) {
0873: throw new IllegalArgumentException("Source object is null");
0874: }
0875: if (target == null) {
0876: throw new IllegalArgumentException("Target object is null");
0877: }
0878: if (preserveStates) {
0879: target.record2().copyPreseveStates(source.record(),
0880: updateableFields, dirtyFieldsOnly);
0881: } else {
0882: target.record2().copy(source.record(), updateableFields,
0883: dirtyFieldsOnly);
0884: }
0885: target.toBeanFields();
0886: }
0887:
0888: /**
0889: * Copies all fields from source record to this record.
0890: *
0891: * @param source source <tt>PersistentObject</tt>
0892: * from source record to this record even if the values are the same
0893: */
0894: public void copy(PersistentObject source) {
0895: copy(source, null, false);
0896: }
0897:
0898: /**
0899: * Copies all fields from source persistent object to this persistent object.
0900: * Target record "dirty" states are set the same as the source record fields "dirty" states
0901: * even if the values are the same
0902: *
0903: * @param source source <tt>PersistentObject</tt>
0904: * from source record to this record even if the values are the same
0905: */
0906: public void copyPreserveStates(PersistentObject source) {
0907: copy(source, null, false, true);
0908: }
0909:
0910: /**
0911: * Right pads character fields to column length with spaces.
0912: *
0913: * @param index
0914: * @param value
0915: * @return Object
0916: */
0917: public String v2c(int index, String value) {
0918: return (String) _record.v2c(index, value);
0919: }
0920:
0921: /**
0922: * Returns <tt>Parameters</tt> object based on values and column types of the record for columns with indeces
0923: * specified with "indeces" parameter. This method will populate parameters regardless of whether they are
0924: * "dirty" flags or nulls
0925: *
0926: * @param indeces
0927: * @return Parameters object based on values and column types of the record for columns with indeces
0928: * specified with "indeces" parameter
0929: */
0930: public Parameters toParameters(int[] indeces) {
0931: return _record.toParameters(indeces);
0932: }
0933:
0934: /**
0935: * Returns <tt>Parameters</tt> object based on values and column types of the record.
0936: * This method will populate parameters only if corresponding fields are
0937: * "dirty" and not nulls
0938: *
0939: * @param primaryKeyOnly if true only primary key columns are considered
0940: * @return Parameters object based on values and column types of the record
0941: */
0942: public Parameters toNotNullParameters(boolean primaryKeyOnly) {
0943: return _record.toNotNullParameters(primaryKeyOnly);
0944: }
0945:
0946: /**
0947: * Returns <tt>Parameters</tt> object based on values and column types of the record.
0948: * This method will populate parameters only if corresponding fields are
0949: * "dirty" and not nulls
0950: *
0951: * @return Parameters object based on values and column types of the record
0952: */
0953: public Parameters toNotNullParameters() {
0954: return _record.toNotNullParameters(false);
0955: }
0956:
0957: /**
0958: * Returns <tt>Parameters</tt> object based on values and column types of the record.
0959: * This method will populate parameters only if corresponding fields are "dirty"
0960: *
0961: * @param primaryKeyOnly if true only primary key columns are considered
0962: * @return Parameters object based on values and column types of the record
0963: */
0964: public Parameters toParameters(boolean primaryKeyOnly) {
0965: return _record.toParameters(primaryKeyOnly);
0966: }
0967:
0968: /**
0969: * Returns <tt>Parameters</tt> object based on values and column types of the record.
0970: * This method will populate parameters only if corresponding fields are "dirty"
0971: *
0972: * @return Parameters object based on values and column types of the record
0973: */
0974: public Parameters toParameters() {
0975: return _record.toParameters(false);
0976: }
0977:
0978: /**
0979: * Add child link with specific name
0980: *
0981: * @param link
0982: * @throws NullPointerException if link has no name set
0983: * @see Link
0984: */
0985: public void addChild(Link link) {
0986: _record.addChild(link);
0987: }
0988:
0989: /**
0990: * Add child link with specific name as ad-hoc link.
0991: * Ad-hoc links are not part of the Link Dependency Graph and hence the objcts they contain
0992: * cannot be inserted/updated/deleted. It is dynamically added read only data.
0993: *
0994: * @param name
0995: * @param data
0996: * @return newly added link
0997: */
0998: public Link addAdHocChild(String name, Object data) {
0999: Link link = new Link(name, data);
1000: _record.addChild(link);
1001: return link;
1002: }
1003:
1004: /**
1005: * Returns record <tt>LinkIterator</tt>
1006: *
1007: * @return <tt>LinkIterator</tt>
1008: */
1009: public LinkIterator linkIterator() {
1010: return _record.linkIterator();
1011: }
1012:
1013: /**
1014: * Returns child link by name
1015: *
1016: * @return child link by name
1017: */
1018: public Link child(String name) {
1019: return _record.getChild(name);
1020: }
1021:
1022: /**
1023: * Returns true if this record has child links
1024: *
1025: * @return true if this record has child links
1026: */
1027: public boolean hasChildren() {
1028: return hasChildren0();
1029: }
1030:
1031: private boolean hasChildren0() {
1032: return _record != null && _record.hasChildren();
1033: }
1034:
1035: /**
1036: * Get child link result w/o
1037: * causing lazy retrieval to fire
1038: *
1039: * @param name
1040: * @return Object
1041: */
1042: public Object getChildObjectStraight(String name) {
1043: return _record.getChildObjectStraight(name);
1044: }
1045:
1046: /**
1047: * Get child link result object
1048: *
1049: * @param name
1050: * @return child link result object
1051: * @throws OdalRuntimePersistencyException if child retrieval from database failed
1052: */
1053: public Object getChildObject(String name) {
1054: try {
1055: return _record.getChildObject(name);
1056: } catch (SQLException e) {
1057: throw new OdalRuntimePersistencyException(
1058: "Cannot get child object", e);
1059: }
1060: }
1061:
1062: /**
1063: * Gets child link result object. If result object is instance of Collection and
1064: * collection size is greater than zero the 1st collection element is returned.
1065: * If result object is instance of Collection and collection size is zero then null
1066: * is returned.
1067: *
1068: * @param name
1069: * @return child link result object. If result object is instance of Collection and
1070: * collection size is greater than zero the 1st collection element is returned.
1071: * If result object is instance of Collection and collection size is zero then null
1072: * is returned.
1073: * @throws OdalRuntimePersistencyException if child retrieval from database failed
1074: */
1075: public Object getFirstChildObject(String name) {
1076: Object value;
1077: try {
1078: value = _record.getChildObject(name);
1079: } catch (SQLException e) {
1080: throw new OdalRuntimePersistencyException(
1081: "Cannot get First Child Object", e);
1082: }
1083: return resolveCollection(value);
1084: }
1085:
1086: /**
1087: * Gets child link result object w/o
1088: * causing lazy retrieval to fire. If result object is instance of Collection and
1089: * collection size is greater than zero the 1st collection element is returned.
1090: * If result object is instance of Collection and collection size is zero then null
1091: * is returned.
1092: *
1093: * @param name
1094: * @return child link result object. If result object is instance of Collection and
1095: * collection size is greater than zero the 1st collection element is returned.
1096: * If result object is instance of Collection and collection size is zero then null
1097: * is returned.
1098: */
1099: public Object getFirstChildObjectStraight(String name) {
1100: Object o = _record.getChildObjectStraight(name);
1101: return resolveCollection(o);
1102: }
1103:
1104: private Object resolveCollection(Object o) {
1105: if (o instanceof Collection) {
1106: Collection collection = (Collection) o;
1107: return collection.size() > 0 ? collection.iterator().next()
1108: : null;
1109: } else {
1110: return o;
1111: }
1112: }
1113:
1114: /**
1115: * Sets result value to link with specific name name
1116: *
1117: * @param name name of child link
1118: * @param value
1119: * @see Link#setResult(Object)
1120: * @see Link#getName()
1121: */
1122: public void setChildObject(String name, Object value) {
1123: _record.setChildObject(name, value);
1124: }
1125:
1126: public String toString() {
1127: StringBuffer buffer = new StringBuffer(super .toString());
1128: buffer.append(" = { Record = ").append(_record).append("} ");
1129: return buffer.toString();
1130: }
1131:
1132: /**
1133: * Returns "deep" string reperesentation of this object
1134: *
1135: * @param persistentObject
1136: * @return "deep" string reperesentation of this object
1137: */
1138: public static String toGenericString(
1139: PersistentObject persistentObject) {
1140: if (persistentObject == null) {
1141: return "null";
1142: } else {
1143: StringBuffer buffer = new StringBuffer(persistentObject
1144: .toString());
1145: if (persistentObject.compound()) {
1146: buffer.append("-> {compoundChildren: ");
1147: for (int i = 1; i < persistentObject.compoundSize(); i++) {
1148: PersistentObject entry = persistentObject
1149: .compoundEntry(i);
1150: buffer.append(toGenericString(entry));
1151: }
1152: buffer.append("} ");
1153: }
1154:
1155: if (persistentObject.hasChildren()) {
1156: buffer.append("-> {complexChildren: ");
1157: for (LinkIterator it = persistentObject.linkIterator(); it
1158: .hasNext();) {
1159: Link link = it.nextLink();
1160: String name = link.getName();
1161: Object result = link.getResult();
1162: String linkSummary = link.getName() == null ? ""
1163: : link.toSummaryString();
1164:
1165: if (result instanceof PersistentObject) {
1166: PersistentObject childObject = (PersistentObject) result;
1167: buffer.append("-> {child ").append(linkSummary)
1168: .append("->{").append(
1169: toGenericString(childObject))
1170: .append("}}");
1171: } else if (result instanceof List) {
1172: List list = (List) result;
1173: buffer.append("-> {child : ").append(
1174: linkSummary).append("->{").append(
1175: " List[").append(list.size()).append(
1176: "]: ").append(name).append(" {[");
1177:
1178: for (int i = 0; i < list.size(); i++) {
1179: String comma = i == 0 ? "" : ", ";
1180: PersistentObject childObject = (PersistentObject) list
1181: .get(i);
1182: buffer.append(comma).append(
1183: toGenericString(childObject));
1184: }
1185: buffer.append("]}}}");
1186: } else {
1187: buffer.append("; {child ").append(linkSummary)
1188: .append(" {").append("null").append(
1189: "}}");
1190: }
1191: }
1192: buffer.append("}");
1193: }
1194: return buffer.toString();
1195: }
1196: }
1197:
1198: //
1199: // Facade to record:
1200: //
1201:
1202: /**
1203: * Returns field value as Object
1204: *
1205: * @param index
1206: * @return field value as Object
1207: */
1208: public Object objectValue(int index) {
1209: return _record.getObject(index);
1210: }
1211:
1212: /**
1213: * Returns field value as String
1214: *
1215: * @param index
1216: * @return field value as String
1217: */
1218: public String stringValue(int index) {
1219: return _record.getString(index);
1220: }
1221:
1222: /**
1223: * Returns field value as Boolean
1224: *
1225: * @param index
1226: * @return field value as Boolean
1227: */
1228: public Boolean booleanValue(int index) {
1229: return _record.getBoolean(index);
1230: }
1231:
1232: /**
1233: * Returns field value as Date
1234: *
1235: * @param index
1236: * @return field value as Date
1237: */
1238: public Date dateValue(int index) {
1239: return _record.getDate(index);
1240: }
1241:
1242: /**
1243: * Returns field value as Object
1244: *
1245: * @param columnName
1246: * @return field value as Object
1247: */
1248: public Object objectValue(String columnName) {
1249: return _record.getObject(columnName);
1250: }
1251:
1252: /**
1253: * Returns field value as String
1254: *
1255: * @param columnName
1256: * @return field value as String
1257: */
1258: public String stringValue(String columnName) {
1259: return _record.getString(columnName);
1260: }
1261:
1262: /**
1263: * Returns field value as Boolean
1264: *
1265: * @param columnName
1266: * @return field value as Boolean
1267: */
1268: public Boolean booleanValue(String columnName) {
1269: return _record.getBoolean(columnName);
1270: }
1271:
1272: /**
1273: * Returns field value as Date
1274: *
1275: * @param columnName
1276: * @return field value as Date
1277: */
1278: public Date dateValue(String columnName) {
1279: return _record.getDate(columnName);
1280: }
1281:
1282: /**
1283: * Return objects key. Its value will be used to identify object in TracingCollection updates.
1284: *
1285: * @return objects key
1286: * @see AbstractPersistentObject#toKey()
1287: */
1288: public Object toKey() {
1289: return super .toKey();
1290: }
1291:
1292: /**
1293: * Marks field as dirty
1294: *
1295: * @param index
1296: */
1297: public void markFieldDirty(int index) {
1298: record().markFieldDirty(index);
1299: }
1300:
1301: /**
1302: * Resets dirty flag
1303: *
1304: * @param index
1305: */
1306: public void unmarkFieldDirty(int index) {
1307: record().unmarkFieldDirty(index);
1308: }
1309:
1310: /**
1311: * Marks all fields as dirty
1312: */
1313: public void markAllFieldsDirty() {
1314: _record.markAllFieldsDirty();
1315: }
1316:
1317: /**
1318: * Resets dirty flags
1319: */
1320: public void unmarkAllFieldsDirty() {
1321: _record.unmarkAllFieldsDirty();
1322: }
1323:
1324: /**
1325: * Returns true if this is complex object
1326: *
1327: * @return true if this is complex object
1328: */
1329: public boolean complex() {
1330: return false;
1331: }
1332:
1333: /**
1334: * Experimental
1335: */
1336: public Link[] inlineLinks() {
1337: return _record.getInlineLinks();
1338: }
1339:
1340: /**
1341: * Marks this object as "InitializedComplex"
1342: */
1343: public void markInitializedComplex() {
1344: if (!_initializedComplex) {
1345: synchronized (this ) {
1346: _initializedComplex = true;
1347: }
1348: }
1349: }
1350:
1351: /**
1352: * Unmarks this object as "InitializedComplex". Also resets LinkDependencyGraph.
1353: */
1354: public void unmarkInitializedComplex() {
1355: if (_initializedComplex) {
1356: synchronized (this ) {
1357: _initializedComplex = false;
1358: if (_record != null) {
1359: _record.setDependencyGraph(null);
1360: }
1361: }
1362: }
1363: }
1364:
1365: /**
1366: * Returns true if this object passed "initialization for complex" stage
1367: *
1368: * @return true if this object passed "initialization for complex" stage
1369: */
1370: public boolean initializedComplex() {
1371: return _initializedComplex;
1372: }
1373:
1374: //
1375: // For external serialization:
1376: //
1377:
1378: /**
1379: * Implementation of Externalizable interface
1380: *
1381: * @param out ObjectOutput
1382: * @throws IOException
1383: * @see java.io.Externalizable
1384: */
1385: public void writeExternal(ObjectOutput out) throws IOException {
1386: invalidateOnFlattened();
1387: _record.writeExternal(out);
1388: writeExternalDescendant(out);
1389: if (compound()) {
1390: for (int i = 1; i < persistentObjects.length; i++) {
1391: PersistentObject persistentObject = persistentObjects[i];
1392: persistentObject.writeExternal(out);
1393: }
1394: }
1395: }
1396:
1397: /**
1398: * Implementation of Externalizable interface
1399: *
1400: * @param in ObjectInput
1401: * @throws IOException
1402: * @throws ClassNotFoundException
1403: * @see java.io.Externalizable
1404: */
1405: public void readExternal(ObjectInput in) throws IOException,
1406: ClassNotFoundException {
1407: invalidateOnFlattened();
1408: _record.readExternal(in);
1409: toBeanFields();
1410: readExternalDescendant(in);
1411: if (compound()) {
1412: for (int i = 1; i < persistentObjects.length; i++) {
1413: PersistentObject persistentObject = persistentObjects[i];
1414: persistentObject.readExternal(in);
1415: }
1416: }
1417: }
1418:
1419: /**
1420: * Auxilliary serialization
1421: *
1422: * @param out ObjectOutput
1423: * @throws IOException
1424: */
1425: public void writeExternalDescendant(ObjectOutput out)
1426: throws IOException {
1427: }
1428:
1429: /**
1430: * Auxilliary deserialization
1431: *
1432: * @param in ObjectInput
1433: * @throws IOException
1434: * @throws ClassNotFoundException
1435: */
1436: public void readExternalDescendant(ObjectInput in)
1437: throws IOException, ClassNotFoundException {
1438: }
1439:
1440: //
1441: // Bean fields manipuilation
1442: //
1443:
1444: /**
1445: * Populates POJO fields
1446: */
1447: public void toBeanFields() {
1448: toBeanFields(this );
1449: }
1450:
1451: /**
1452: * Populates POJO fields of this PersistentObject from Record fields
1453: * of sourcePersistentObject passed as parameter
1454: *
1455: * @param sourcePersistentObject
1456: */
1457: public void toBeanFields(PersistentObject sourcePersistentObject) {
1458: }
1459:
1460: public void fromBeanFields() {
1461: fromBeanFields(this );
1462: }
1463:
1464: /**
1465: * Populates Record fields of this PersistentObject from POJO fields
1466: * of sourcePersistentObject passed as parameter
1467: *
1468: * @param sourcePersistentObject
1469: */
1470: public void fromBeanFields(PersistentObject sourcePersistentObject) {
1471: }
1472:
1473: /**
1474: * Sets State.DATA_SAVED to PersistentObject passed as parameter
1475: *
1476: * @param persistentObject PersistentObject which state is to be set
1477: */
1478: protected void fromBeanFieldsDataSaved(
1479: PersistentObject persistentObject) {
1480: fromBeanFields(persistentObject, State.DATA_SAVED);
1481: }
1482:
1483: /**
1484: * Sets State to PersistentObject passed as parameter
1485: *
1486: * @param persistentObject PersistentObject which state is to be set
1487: * @param state State to set
1488: */
1489: protected void fromBeanFields(PersistentObject persistentObject,
1490: State state) {
1491: persistentObject.record().setState(state);
1492: }
1493:
1494: /**
1495: * Return true if object is flattened (its record == null)
1496: *
1497: * @return true if object is flattened
1498: */
1499: public boolean flattened() {
1500: return _record == null;
1501: }
1502:
1503: /**
1504: * @throws OdalRuntimePersistencyException
1505: * if this object is flattened
1506: */
1507: protected void invalidateOnFlattened() {
1508: if (flattened()) {
1509: throw new OdalRuntimePersistencyException(
1510: "Illegal attempt to use record on flattened object");
1511: }
1512: }
1513:
1514: //
1515: // Flatten related:
1516: //
1517:
1518: /**
1519: * Override it in descendants to perform children "flattening"
1520: */
1521: protected void doFlatten() {
1522: }
1523:
1524: /**
1525: * Override it in descendants to perform children "pre-flattening"
1526: */
1527: protected void doPreFlatten() {
1528: }
1529:
1530: /**
1531: * Flattens <tt>PersistentObject</tt> passed as parameter
1532: *
1533: * @param persistentObject <tt>PersistentObject</tt> to be flattened
1534: * @return <tt>PersistentObject</tt> passed as parameter
1535: */
1536: protected static PersistentObject flatten(
1537: PersistentObject persistentObject) {
1538: if (persistentObject != null) {
1539: persistentObject.flatten();
1540: }
1541: return persistentObject;
1542: }
1543:
1544: protected void flatten0() {
1545: doPreFlatten();
1546: _record = null;
1547: doFlatten();
1548: // return this;
1549: }
1550:
1551: //
1552: // Unflatten related:
1553: //
1554:
1555: /**
1556: * Override it in descendants to perform children "unflattening"
1557: */
1558: protected void doUnflatten() {
1559: }
1560:
1561: protected void unflatten0() {
1562: fromBeanFields();
1563: doUnflatten();
1564: // return this;
1565: }
1566:
1567: /**
1568: * Unflattens link.
1569: *
1570: * @param parentLink Link object to be unflattened
1571: * @param childName name of child object to be unflattened and set
1572: * @param childPersistent <tt>PersistentObject</tt> to be unflatten and set to this PersistentObject
1573: * under name specified by <tt>childName</tt> parameter
1574: */
1575: protected static PersistentObject unflatten(Link parentLink,
1576: String childName, PersistentObject childPersistent) {
1577: if (childPersistent != null) {
1578: childPersistent.unflatten();
1579: parentLink.setChildObject(childName, childPersistent);
1580: }
1581: return childPersistent;
1582: }
1583:
1584: /**
1585: * Unflattens link.
1586: *
1587: * @param parentLink Link object to be unflattened
1588: * @param childName name of child object to be unflattened and set
1589: * @param slaves Collection<PersistentObject> to be unflatten and set to this PersistentObject
1590: * under name specified by <tt>childName</tt> parameter
1591: */
1592: protected static void unflatten(Link parentLink, String childName,
1593: Collection slaves) {
1594: if (slaves != null) {
1595: for (Iterator iterator = slaves.iterator(); iterator
1596: .hasNext();) {
1597: PersistentObject persistent = (PersistentObject) iterator
1598: .next();
1599: if (persistent != null) {
1600: persistent.unflatten();
1601: }
1602: }
1603: parentLink.setChildObject(childName, slaves);
1604: }
1605: }
1606:
1607: /**
1608: * Flattens collection of persistent objects
1609: *
1610: * @param slaves Collection<PersistentObject> to be flattened
1611: */
1612: protected static void flatten(Collection slaves) {
1613: if (slaves != null) {
1614: for (Iterator iterator = slaves.iterator(); iterator
1615: .hasNext();) {
1616: PersistentObject persistent = (PersistentObject) iterator
1617: .next();
1618: flatten(persistent);
1619: }
1620: }
1621: }
1622:
1623: /**
1624: * If this object is flattened returns value passed as parameter.<br>
1625: * Otherwise:<br>
1626: * If this object is not flattened gets child link result object. If result object is instance of Collection and
1627: * collection size is greater than zero the 1st collection element is returned.
1628: * If result object is instance of Collection and collection size is zero then null
1629: * is returned.
1630: *
1631: * @param name
1632: * @return If this object is flattened - value passed as parameter.<br>Otherwise:<br> If child link result object. If result object is instance of Collection and
1633: * collection size is greater than zero the 1st collection element is returned.
1634: * If result object is instance of Collection and collection size is zero then null
1635: * is returned.
1636: */
1637: protected Object getFirstChildObject(String name, Object value) {
1638: if (!flattened()) {
1639: value = getFirstChildObject(name);
1640: }
1641: return value;
1642: }
1643:
1644: /**
1645: * If this object is flattened returns value passed as parameter.<br>
1646: * Otherwise:<br>
1647: * If this object is not flattened gets child link result object w/o
1648: * causing lazy retrieval to fire. If result object is instance of Collection and
1649: * collection size is greater than zero the 1st collection element is returned.
1650: * If result object is instance of Collection and collection size is zero then null
1651: * is returned.
1652: *
1653: * @param name
1654: * @return If this object is flattened - value passed as parameter.<br>Otherwise:<br> If child link result object. If result object is instance of Collection and
1655: * collection size is greater than zero the 1st collection element is returned.
1656: * If result object is instance of Collection and collection size is zero then null
1657: * is returned.
1658: */
1659: protected Object getFirstChildObjectStraight(String name,
1660: Object value) {
1661: if (!flattened()) {
1662: value = getFirstChildObjectStraight(name);
1663: }
1664: return value;
1665: }
1666:
1667: /**
1668: * If object is flattened then returns value specified by 'value' parameter else
1669: * retrieves value by getChildObject(name) method
1670: *
1671: * @param name child name
1672: * @param value default value if object flattened
1673: * @return If object is flattened - value specified by 'value' parameter else
1674: * retrieves value by getChildObject(name) method
1675: */
1676: protected Object getChildObject(String name, Object value) {
1677: if (!flattened()) {
1678: value = getChildObject(name);
1679: }
1680: return value;
1681: }
1682:
1683: /**
1684: * If object is flattened then returns value specified by 'value' parameter else
1685: * retrieves value by getChildObject(name) method w/o
1686: * causing lazy retrieval to fire
1687: *
1688: * @param name child name
1689: * @param value default value if object flattened
1690: * @return Object If object is flattened then - value specified by 'value' parameter else
1691: * retrieves value by getChildObject(name) method w/o
1692: * causing lazy retrieval to fire
1693: */
1694: protected Object getChildObjectStraight(String name, Object value) {
1695: if (!flattened()) {
1696: value = getChildObjectStraight(name);
1697: }
1698: return value;
1699: }
1700:
1701: /**
1702: * Sets child object value if this <tt>PersistentObject</tt> is not flattened.
1703: * Always returns newValue passed as parameter
1704: *
1705: * @param name
1706: * @param newValue
1707: * @return Object newValue parameter
1708: */
1709: protected Object setChildObjectSafe(String name, Object newValue) {
1710: if (!flattened()) {
1711: setChildObject(name, newValue);
1712: }
1713: return newValue;
1714: }
1715:
1716: /**
1717: * Performs Record post initialization activities.
1718: */
1719: protected void postInitializeRecord() {
1720: }
1721:
1722: /**
1723: * Returns Boolean.TRUE if all newly created child Tracing Collections have to be forced to "trace on" mode,
1724: * Boolean.FALSE if all newly created child Tracing Collections have to be forced to "trace off" mode,
1725: * null if all newly created child Tracing Collections have to be left in default trace mode.
1726: *
1727: * @return Boolean.TRUE if all newly created child Tracing Collections have to be forced to "trace on" mode,
1728: * Boolean.FALSE if all newly created child Tracing Collections have to be forced to "trace off" mode,
1729: * null if all newly created child Tracing Collections have to be left in default trace mode.
1730: */
1731: public Boolean traced() {
1732: return _trace;
1733: }
1734:
1735: /**
1736: * Indicates that all newly created child Tracing Collections have to be forced to "trace on" mode.
1737: *
1738: * @return itself
1739: */
1740: public PersistentObject traceOn() {
1741: this ._trace = Boolean.TRUE;
1742: return this ;
1743: }
1744:
1745: /**
1746: * Indicates that all newly created child Tracing Collections have to be forced to "trace off" mode.
1747: * It makes sense to do it when your child objects are from the database and you do not want them
1748: * to be saved again.
1749: *
1750: * @return itself
1751: */
1752: public PersistentObject traceOff() {
1753: this ._trace = Boolean.FALSE;
1754: return this ;
1755: }
1756:
1757: /**
1758: * Immediately forces all child Tracing Collections have to be forced to "trace on" mode.
1759: *
1760: * @return itself
1761: */
1762: public PersistentObject traceOnAll() {
1763: if (complex()) {
1764: Link link = toLink();
1765: for (LinkIterator it = link.linkIterator(); it.hasNext();) {
1766: Link childLink = it.nextLink();
1767: Object result = childLink.getResult();
1768: if (result instanceof TracingCollection) {
1769: TracingCollection tracingCollection = (TracingCollection) result;
1770: tracingCollection.setTrace();
1771: }
1772: }
1773: }
1774: return this ;
1775: }
1776:
1777: /**
1778: * Immediately forces all child Tracing Collections have to be forced to "trace off" mode.
1779: *
1780: * @return itself
1781: */
1782: public PersistentObject traceOffAll() {
1783: if (complex()) {
1784: Link link = toLink();
1785: for (LinkIterator it = link.linkIterator(); it.hasNext();) {
1786: Link childLink = it.nextLink();
1787: Object result = childLink.getResult();
1788: if (result instanceof TracingCollection) {
1789: TracingCollection tracingCollection = (TracingCollection) result;
1790: tracingCollection.unsetTrace();
1791: }
1792: }
1793: }
1794: return this ;
1795: }
1796:
1797: /**
1798: * Immediately forces all Tracing Collections passed as paramater have to "trace on" mode,
1799: * meaning that all object tree collections will trace al the changes to them after.
1800: *
1801: * @param collection Collection
1802: * @return itself
1803: */
1804: public static Collection traceOnAll(Collection collection) {
1805: for (Iterator iterator = collection.iterator(); iterator
1806: .hasNext();) {
1807: PersistentObject persistent = (PersistentObject) iterator
1808: .next();
1809: persistent.traceOnAll();
1810: }
1811: return collection;
1812: }
1813:
1814: /**
1815: * This method will be called in descendants on lazy collection instanciation.
1816: * It will set proper tracing mode if needed
1817: *
1818: * @param collection
1819: */
1820: protected void handleAddCollection(Collection collection) {
1821: if (traced() != null && collection instanceof TracingCollection) {
1822: TracingCollection tracingCollection = (TracingCollection) collection;
1823: boolean setTrace = traced().booleanValue();
1824: if (setTrace) {
1825: tracingCollection.setTrace();
1826: } else {
1827: tracingCollection.unsetTrace();
1828: }
1829: }
1830: }
1831: }
|