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.core.impl;
0010:
0011: import com.completex.objective.components.persistency.AbstractPersistentObject;
0012: import com.completex.objective.components.persistency.Cloneable;
0013: import com.completex.objective.components.persistency.LifeCycleController;
0014: import com.completex.objective.components.persistency.Link;
0015: import com.completex.objective.components.persistency.OdalPersistencyException;
0016: import com.completex.objective.components.persistency.OdalRuntimePersistencyException;
0017: import com.completex.objective.components.persistency.PersistentObject;
0018: import com.completex.objective.components.persistency.core.CircularDependencyError;
0019: import com.completex.objective.components.persistency.type.Tracer;
0020: import com.completex.objective.components.persistency.type.TracingCollection;
0021:
0022: import java.util.ArrayList;
0023: import java.util.Collection;
0024: import java.util.Iterator;
0025: import java.util.LinkedHashMap;
0026: import java.util.LinkedHashSet;
0027: import java.util.List;
0028: import java.util.Map;
0029: import java.util.Set;
0030: import java.util.Collections;
0031:
0032: /**
0033: * Class that determines order of inserts/updates/deletes/selects for complex persistent objects
0034: *
0035: * @author Gennady Krizhevsky
0036: */
0037: public class LinkDependencyGraph implements Cloneable {
0038:
0039: private LinkHolder linkHolder;
0040: private boolean print = false;
0041:
0042: public LinkDependencyGraph() {
0043: }
0044:
0045: /**
0046: *
0047: * @param parent persistent object
0048: */
0049: public LinkDependencyGraph(AbstractPersistentObject parent) {
0050: assemble(parent);
0051: }
0052:
0053: /**
0054: * Assemble LinkDependencyGraph ordering links by dependecies
0055: *
0056: * @param parent
0057: */
0058: public void assemble(AbstractPersistentObject parent) {
0059: assemble(parent, false);
0060: }
0061:
0062: /**
0063: * Assemble LinkDependencyGraph ordering links by dependecies
0064: *
0065: * @param parent
0066: * @param reset indicator when set true re-assembling is performed
0067: */
0068: public void assemble(AbstractPersistentObject parent, boolean reset) {
0069: if (!reset && hasMetaAssembly()) {
0070: return;
0071: }
0072: Context context = new Context();
0073: assembleLocal(parent, context);
0074: assemblySecondPass(context);
0075: }
0076:
0077: /**
0078: * Get meta assembly Link by index
0079: * @param index
0080: * @return meta assembly Link
0081: */
0082: public Link getMetaAssemblyLink(int index) {
0083: return linkHolder == null ? null : linkHolder
0084: .getMetaAssemblyLink(index);
0085: }
0086:
0087: /**
0088: *
0089: * @return metaAssemblySize
0090: */
0091: public int metaAssemblySize() {
0092: return linkHolder == null ? 0 : linkHolder.metaAssemblySize();
0093: }
0094:
0095: public boolean hasMetaAssembly() {
0096: return linkHolder != null && linkHolder.hasMetaAssembly();
0097: }
0098:
0099: private void assembleLocal(AbstractPersistentObject parent,
0100: Context context) {
0101: try {
0102: Link rootLink = parent.toLink().setCascadeAll();
0103: if (parent.hasChildren()) {
0104: assemble0(rootLink, parent.linkIterator(), context);
0105: }
0106: println(metaAssemblyToString(context.metaAssemblyMap));
0107: assembleOne(null, rootLink, context.metaAssemblyMap);
0108: } catch (StackOverflowError e) {
0109: String message = "\n";
0110: message += " StackOverflowError is caught probably due to circular dependency, look at following current parent & child links which are probably circularly dependent: \n";
0111: message += " currParentLink = " + context.currParentLink
0112: + "\n";
0113: message += " currChildLink = " + context.currChildLink
0114: + "\n";
0115: throw new CircularDependencyError(message);
0116: }
0117: }
0118:
0119: private void assemble0(Link parentLink, LinkIterator it,
0120: Context context) {
0121: context.currParentLink = parentLink;
0122: for (; it.hasNext();) {
0123: Link childLink = it.nextLink();
0124: context.currChildLink = childLink;
0125: assemble007(parentLink, childLink, context);
0126: }
0127: }
0128:
0129: private void assemble007(Link parentLink, Link childLink,
0130: Context context) {
0131: assembleOne(parentLink, childLink, context.metaAssemblyMap);
0132: if (childLink.hasChildren()) {
0133: assemble0(childLink, childLink.linkIterator(), context);
0134: }
0135: }
0136:
0137: /**
0138: * Creates map keys of which are all the persistent objects in the graph,
0139: * values - List of objects the key object depends on
0140: *
0141: * @param parent
0142: */
0143: void assembleOne(Link parent, Link child, LinkedHashMap assembly) {
0144: if (child.isInsertBeforeParent()) {
0145: addDependant(parent, child, assembly);
0146: } else {
0147: addDependant(child, parent, assembly);
0148: }
0149: }
0150:
0151: private void addDependant(Link dependant, Link depender,
0152: LinkedHashMap assembly) {
0153: Set dependsOn = (Set) assembly.get(dependant);
0154: if (dependsOn == null) {
0155: dependsOn = new LinkedHashSet();
0156: println("Put dependant " + dependant);
0157: println(" Put depender " + depender);
0158: if (depender != null && !dependant.isCascadeDelete()) {
0159: // If dependant (for insert) is excluded from delete -
0160: // exclude the depender also: for deletes
0161: // the dependency order is opposite
0162: depender.setCascadeDelete(false);
0163: }
0164:
0165: if (depender != null && !depender.isCascadeInsert()) {
0166: dependant.setCascadeInsert(false);
0167: }
0168:
0169: if (depender != null && !depender.isCascadeUpdate()) {
0170: dependant.setCascadeUpdate(false);
0171: }
0172:
0173: assembly.put(dependant, dependsOn);
0174: }
0175: if (depender != null) {
0176: dependsOn.add(depender);
0177: }
0178: }
0179:
0180: //
0181: //
0182: // Assembly 2nd pass:
0183: //
0184: //
0185:
0186: /**
0187: * 1) Cycle by dependant
0188: * 2) find all the dependers
0189: * 3) cycle by dependers
0190: * 4) from each depender find if it is in the dependants
0191: * 5) if yes do 1)
0192: * 6) if not - add depender to final assembly
0193: * 7) add dependant to final assembly
0194: */
0195: private void assemblySecondPass(Context context) {
0196: LinkedHashSet finalAssemblySet = new LinkedHashSet();
0197: for (Iterator ait = context.metaAssemblyMap.keySet().iterator(); ait
0198: .hasNext();) {
0199: Link dependant = (Link) ait.next();
0200: assemblySecondPass0(dependant, finalAssemblySet,
0201: context.metaAssemblyMap, 0);
0202: finalAssemblySet.add(dependant);
0203: }
0204:
0205: ArrayList finalAssemblyList = new ArrayList(finalAssemblySet
0206: .size());
0207: for (Iterator it = finalAssemblySet.iterator(); it.hasNext();) {
0208: Link link = (Link) it.next();
0209: finalAssemblyList.add(link);
0210: }
0211: context.metaAssembly = new Link[finalAssemblyList.size()];
0212: finalAssemblyList.toArray(context.metaAssembly);
0213: for (int i = 0; i < context.metaAssembly.length; i++) {
0214: context.metaAssembly[i].setDependencyIndex(i);
0215: }
0216: linkHolder = new LinkHolder(context.metaAssembly);
0217: }
0218:
0219: private boolean assemblySecondPass0(Link dependant,
0220: LinkedHashSet finalAssemblySet, LinkedHashMap assembly,
0221: int level) {
0222: level++;
0223: boolean rc = false;
0224: Set dependers = (Set) assembly.get(dependant);
0225: if (dependers != null && dependers.size() > 0) {
0226: for (Iterator it = dependers.iterator(); it.hasNext();) {
0227: Link depender = (Link) it.next();
0228: println("depender[" + level + "] = " + depender);
0229: if (assembly.containsKey(depender)) {
0230: rc = assemblySecondPass0(depender,
0231: finalAssemblySet, assembly, level);
0232: }
0233: if (!finalAssemblySet.contains(depender)) {
0234: finalAssemblySet.add(depender);
0235: }
0236: }
0237: } else {
0238: finalAssemblySet.add(dependant);
0239: rc = true;
0240: }
0241: return rc;
0242: }
0243:
0244: //
0245: //
0246: // Walk is simple now -
0247: //
0248: //
0249:
0250: /**
0251: * @param reverseOrder - process tree from bottom to top
0252: * (as opposed to from top to bottom) - false for inserts/updates, true for deletes
0253: * @param visitor
0254: */
0255: public int walk(boolean reverseOrder, Visitor visitor)
0256: throws OdalPersistencyException {
0257: LinkAssemblyMeta meta = linkHolder.getMeta();
0258:
0259: //
0260: // calculate starting point of the graph for delete or insert:
0261: // it's determined by the break in cascade delete or insert:
0262: //
0263: boolean complexDirty = complexDirty(visitor);
0264:
0265: ArrayList[] finalAssemblies = getFinalAssemblies();
0266: ExtraParents extraParents = new ExtraParents();
0267: int rc = 0;
0268: Set visited = new LinkedHashSet();
0269: int size = finalAssemblies.length;
0270: for (int i = 0; i < size; i++) {
0271: int k = reverseOrder ? (size - i - 1) : i;
0272: ArrayList links = finalAssemblies[k];
0273: Link metaLink = meta.getLink(k);
0274: if (links != null) {
0275: boolean bypassForDelete = ModifyVisitorType
0276: .isDeleteType(visitor)
0277: && !metaLink.isCascadeDelete();
0278: boolean bypassForInsert = ModifyVisitorType
0279: .isInsertType(visitor)
0280: && !metaLink.isCascadeInsert();
0281: boolean bypassForUpdate = ModifyVisitorType
0282: .isUpdateType(visitor)
0283: && !metaLink.isCascadeUpdate();
0284: boolean bypass = (bypassForDelete || bypassForInsert || bypassForUpdate);
0285: if (!bypass) {
0286: for (Iterator iterator = links.iterator(); iterator
0287: .hasNext();) {
0288: Link link = (Link) iterator.next();
0289: resetTracingOnInsertOrDelete(link, visitor);
0290:
0291: //
0292: // populate link with meta data:
0293: //
0294: link.setParentIndeces(metaLink
0295: .getParentIndeces());
0296: link.setThisIndeces(metaLink.getThisIndeces());
0297: try {
0298:
0299: rc += walk007(link, visitor, visited,
0300: complexDirty, finalAssemblies,
0301: extraParents);
0302: } catch (OdalPersistencyException e) {
0303: throw e;
0304: }
0305: }
0306: }
0307: }
0308: }
0309: visited.clear();
0310: return rc;
0311: }
0312:
0313: private boolean complexDirty(Visitor visitor) {
0314: boolean complexDirty = false;
0315: if (visitor.getType() == ModifyVisitorType.UPDATE) {
0316: complexDirty = dirty();
0317: }
0318: return complexDirty;
0319: }
0320:
0321: private void resetTracingOnInsertOrDelete(Link link, Visitor visitor) {
0322: if (link != null && ModifyVisitorType.isInsertOrDelete(visitor)
0323: && link.hasChildren()) {
0324: for (LinkIterator it = link.linkIterator(); it.hasNext();) {
0325: Link childLink = it.nextLink();
0326: if (childLink != null
0327: && childLink.getResult() != null
0328: && (childLink.getResult() instanceof TracingCollection)) {
0329: TracingCollection tracingCollection = (TracingCollection) childLink
0330: .getResult();
0331: tracingCollection.clearTrace();
0332: }
0333: }
0334: }
0335: }
0336:
0337: private ArrayList[] getFinalAssemblies() {
0338: LinkedHashMap finalAssemblyMap = linkHolder
0339: .getDataAssemblyMap();
0340: Collection collection = finalAssemblyMap.values();
0341: ArrayList[] finalAssemblies = new ArrayList[collection.size()];
0342:
0343: int m = 0;
0344: for (Iterator mapIterator = collection.iterator(); mapIterator
0345: .hasNext(); m++) {
0346: finalAssemblies[m] = (ArrayList) mapIterator.next();
0347: for (int i = 0; i < finalAssemblies[m].size(); i++) {
0348: Link link = (Link) finalAssemblies[m].get(i);
0349: if (link != null) {
0350: link.setDependencyIndex(m);
0351: }
0352:
0353: }
0354: }
0355: return finalAssemblies;
0356: }
0357:
0358: private int walk007(Link link, Visitor visitor, Set visited,
0359: boolean complexDirty, ArrayList[] finalAssemblies,
0360: ExtraParents extraParents) throws OdalPersistencyException {
0361: int rc = 0;
0362: Object result = link.getResult();
0363: LifeCycleController controller = link.getLifeCycleController();
0364: if (result != null) {
0365: if (result instanceof AbstractPersistentObject) {
0366: rc += visit0((AbstractPersistentObject) result,
0367: visitor, visited, controller, link,
0368: complexDirty, finalAssemblies, extraParents);
0369: } else if (result instanceof TracingCollection) {
0370: //
0371: // If this is tracing collections then operation is generalixzed update.
0372: // To exclude those entries that has been deleted or just inserted -
0373: // check if the entry is traced. If so - it is deleted or inserted - skip it:
0374: //
0375: TracingCollection list = (TracingCollection) result;
0376: for (Iterator iterator = list.iterator(); iterator
0377: .hasNext();) {
0378: PersistentObject persistentObject = (PersistentObject) iterator
0379: .next();
0380: if (!list.containsEntry(persistentObject)) {
0381: rc += visit0(persistentObject, visitor,
0382: visited, controller, link,
0383: complexDirty, finalAssemblies,
0384: extraParents);
0385: }
0386: }
0387: } else if (result instanceof Collection) {
0388: Collection list = (Collection) result;
0389: for (Iterator iterator = list.iterator(); iterator
0390: .hasNext();) {
0391: AbstractPersistentObject persistentObject = (AbstractPersistentObject) iterator
0392: .next();
0393: rc += visit0(persistentObject, visitor, visited,
0394: controller, link, complexDirty,
0395: finalAssemblies, extraParents);
0396: }
0397: } else {
0398: throw new IllegalArgumentException("Unknown type "
0399: + result.getClass().getName());
0400: }
0401:
0402: }
0403: return rc;
0404: }
0405:
0406: private int visit0(AbstractPersistentObject persistent,
0407: Visitor visitor, Set visited,
0408: LifeCycleController controller, Link link,
0409: boolean complexDirty, ArrayList[] finalAssemblies,
0410: ExtraParents extraParents) throws OdalPersistencyException {
0411: int rc = 0;
0412: if (!visited.contains(persistent)) {
0413: insertDependentIndices(visitor, link,
0414: (PersistentObject) persistent, finalAssemblies,
0415: extraParents);
0416: rc = visitor.visit(persistent, controller,
0417: persistent == visitor.getRoot(), complexDirty);
0418: visited.add(persistent);
0419: }
0420: return rc;
0421: }
0422:
0423: /**
0424: * Populate indeces in dependent object if there are no values. it will take care of autogenerated parent
0425: * fields - children's ones will be populated automatically
0426: *
0427: * @param visitor
0428: * @param link
0429: * @param persistent
0430: * @param finalAssemblies
0431: * @param extraParents
0432: */
0433: private void insertDependentIndices(Visitor visitor, Link link,
0434: PersistentObject persistent, ArrayList[] finalAssemblies,
0435: ExtraParents extraParents) {
0436: if (visitor.getType() == ModifyVisitorType.INSERT) {
0437: if (link.getParentLink() != null
0438: && link.getDependencyIndex() > 0
0439: && link.getParentIndeces() != null
0440: && link.getParentLink().getResult() != null) {
0441: insertDependentIndicesDirect(link, persistent,
0442: finalAssemblies, extraParents);
0443: } else { // Case of reversed dependency - slave is root object ...
0444: insertDependentIndicesReversed(persistent, link,
0445: extraParents);
0446: }
0447: }
0448: }
0449:
0450: private void insertDependentIndicesReversed(
0451: PersistentObject persistent, Link link,
0452: ExtraParents extraParents) {
0453: if (persistent != null
0454: && persistent.toLink() != null
0455: && persistent.toLink().getResult() instanceof PersistentObject) {
0456: Link parentLink = ((PersistentObject) persistent.toLink()
0457: .getResult()).toLink();
0458: if (parentLink.hasChildren()) {
0459: for (LinkIterator it = parentLink.linkIterator(); it
0460: .hasNext();) {
0461: Link childLink = it.nextLink();
0462: if (childLink.getDependencyIndex() < link
0463: .getDependencyIndex()) {
0464: Object result = childLink.getResult();
0465: PersistentObject childPersistentObject = null;
0466: // It can be collection of size 1:
0467: if (result instanceof Collection) {
0468: Collection collection = (Collection) result;
0469: if (!collection.isEmpty()) {
0470: childPersistentObject = (PersistentObject) collection
0471: .iterator().next();
0472: }
0473: } else if (result instanceof PersistentObject) {
0474: childPersistentObject = ((PersistentObject) result);
0475: } else if (result != null) {
0476: throw new OdalRuntimePersistencyException(
0477: "Unsupported result type " + result);
0478: }
0479: if (childPersistentObject != null) {
0480: int[] parentIndeces = childPersistentObject
0481: .toLink().getParentIndeces();
0482: int[] this Indeces = childPersistentObject
0483: .toLink().getThisIndeces();
0484:
0485: for (int i = 0; i < this Indeces.length; i++) {
0486: int this Index = this Indeces[i];
0487: int parentIndex = parentIndeces[i];
0488: persistent.record().setObject(
0489: parentIndex,
0490: childPersistentObject.record()
0491: .getObject(this Index));
0492: }
0493: }
0494: }
0495: }
0496: }
0497: }
0498: }
0499:
0500: private void insertDependentIndicesDirect(Link link,
0501: PersistentObject persistent, ArrayList[] finalAssemblies,
0502: ExtraParents extraParents) {
0503: if (link.getParentLink().getResult() instanceof PersistentObject) {
0504: Link parentLink = link.getParentLink();
0505: PersistentObject parentObject = (PersistentObject) parentLink
0506: .getResult();
0507: insertIndicesOne(link, persistent, parentObject);
0508: // New stuff to populate extra indices
0509: insertExtraDependentIndicesDirect(parentLink,
0510: finalAssemblies, link, persistent, extraParents);
0511: }
0512:
0513: //
0514: // Insert extra parent indices:
0515: //
0516: List extraParentLinks = extraParents.getExtraParents(link);
0517: for (int i = 0; i < extraParentLinks.size(); i++) {
0518: Link parentLink = (Link) extraParentLinks.get(i);
0519: if (parentLink.getResult() instanceof PersistentObject) {
0520: PersistentObject parentObject = (PersistentObject) parentLink
0521: .getResult();
0522: insertIndicesOne(parentLink, parentObject, persistent);
0523: }
0524: }
0525: }
0526:
0527: private void insertExtraDependentIndicesDirect(Link parentLink,
0528: ArrayList[] finalAssemblies, Link link,
0529: PersistentObject persistent, ExtraParents extraParents) {
0530: int dependencyIndex = parentLink.getDependencyIndex();
0531: ArrayList links = finalAssemblies[dependencyIndex];
0532: for (int i = 0; i < links.size(); i++) {
0533: Link dependentLink = (Link) links.get(i);
0534: if (dependentLink.hasChildren()
0535: && dependentLink.getResult() instanceof PersistentObject) {
0536: PersistentObject extraParentObject = (PersistentObject) dependentLink
0537: .getResult();
0538: for (LinkIterator it = dependentLink.linkIterator(); it
0539: .hasNext();) {
0540: Link extraParentLink = it.nextLink();
0541: if (extraParentLink != link.getParentLink()
0542: && extraParentLink.getResult() == persistent) {
0543: // insertIndicesOne(link, persistent, extraParentObject);
0544: if (link.getResult() != null) {
0545: extraParents.addExtraParent(dependentLink,
0546: link);
0547: }
0548: }
0549: }
0550: }
0551:
0552: }
0553: }
0554:
0555: private void insertIndicesOne(Link link,
0556: PersistentObject childObject, PersistentObject parentObject) {
0557: setDependentKeys(link, childObject, parentObject);
0558: }
0559:
0560: /**
0561: * Utility method that set dependent values from child to parent or from parent to child PersistentObject
0562: * based on Link.isInsertBeforeParent(), Link.getDependencyIndex(), Link.getThisIndeces() != null,
0563: * Link.getParentIndeces() methods. Dependent values usually
0564: * those based on primary/foreign keys relations
0565: *
0566: * @param link one of the parentObject links establishing relationship to childObject
0567: * @param childObject
0568: * @param parentObject
0569: */
0570: public static void setDependentKeys(Link link,
0571: PersistentObject childObject, PersistentObject parentObject) {
0572: if (link.getThisIndeces() != null
0573: && link.getParentIndeces() != null) {
0574: for (int i = 0; i < link.getParentIndeces().length; i++) {
0575: int childIndex = link.getThisIndeces()[i];
0576: int parentIndex = link.getParentIndeces()[i];
0577: if (!link.isInsertBeforeParent()
0578: && link.getDependencyIndex() > link
0579: .getParentLink().getDependencyIndex()) {
0580: setDependentIndex(parentObject, parentIndex,
0581: childObject, childIndex);
0582: } else {
0583: setDependentIndex(childObject, childIndex,
0584: parentObject, parentIndex);
0585: }
0586: }
0587: }
0588: }
0589:
0590: static void setDependentIndex(PersistentObject parentObject,
0591: int parentIndex, PersistentObject persistentObject,
0592: int this Index) {
0593: Object parentValue = parentObject.record().getObject(
0594: parentIndex);
0595: persistentObject.record().setObject(this Index, parentValue);
0596: }
0597:
0598: public String toString() {
0599: return super .toString() + ": {\n" + metaAssemblyToString()
0600: + "}";
0601: }
0602:
0603: /**
0604: *
0605: * @param metaAssemblyMap
0606: * @return metaAssemblyMap as String
0607: */
0608: public String metaAssemblyToString(LinkedHashMap metaAssemblyMap) {
0609: if (metaAssemblyMap == null) {
0610: return "null";
0611: }
0612: String indent = " ";
0613: StringBuffer buffer = new StringBuffer();
0614: int count = 0;
0615: for (Iterator it = metaAssemblyMap.keySet().iterator(); it
0616: .hasNext();) {
0617: Object key = it.next();
0618: Object value = metaAssemblyMap.get(key);
0619: buffer.append(indent).append("Assembly line[").append(
0620: ++count).append("]; <dependant> = ").append(key)
0621: .append("; <dependsOn> = ").append(value).append(
0622: "\n");
0623: }
0624: return buffer.toString();
0625: }
0626:
0627: /**
0628: *
0629: * @return meta assembly as string
0630: */
0631: public String metaAssemblyToString() {
0632: return linkHolder.metaAssemblyToString();
0633: }
0634:
0635: private void println(String s) {
0636: if (print) {
0637: System.err.println(s);
0638: }
0639: }
0640:
0641: /**
0642: *
0643: * @return copy of this object
0644: * @throws CloneNotSupportedException
0645: */
0646: public Object clone() throws CloneNotSupportedException {
0647: LinkDependencyGraph graph = (LinkDependencyGraph) super .clone();
0648: graph.linkHolder = (LinkHolder) linkHolder.clone();
0649: return graph;
0650: }
0651:
0652: /**
0653: * Add link addToAssembly at specific path
0654: *
0655: * @param linkPath
0656: * @param link
0657: */
0658: public void addToAssembly(String linkPath, Link link) {
0659: linkHolder.addLink(linkPath, link);
0660: }
0661:
0662: /**
0663: * Traverses the dependecy graph and determines if any of NON-BYPASSED link entries is dirty
0664: *
0665: * @return true if at least one of non-bypassed entries is dirty
0666: */
0667: public boolean dirty() {
0668: LinkedHashMap map = linkHolder.getDataAssemblyMap();
0669: for (Iterator it = map.keySet().iterator(); it.hasNext();) {
0670: String key = (String) it.next();
0671: List links = (List) map.get(key);
0672: for (Iterator iterator = links.iterator(); iterator
0673: .hasNext();) {
0674: Link link = (Link) iterator.next();
0675: Link metaLink = linkHolder.getMeta().getLink(key);
0676: boolean bypassForDelete = !metaLink.isCascadeDelete();
0677: boolean bypassForInsert = !metaLink.isCascadeInsert();
0678: boolean bypassForUpdate = !metaLink.isCascadeUpdate();
0679: boolean bypass = bypassForDelete && bypassForInsert
0680: && bypassForUpdate;
0681: if (!bypass) {
0682: Object result = link.getResult();
0683: if (result != null
0684: && result instanceof AbstractPersistentObject
0685: && !bypassForUpdate) {
0686: if (((AbstractPersistentObject) result).dirty()) {
0687: return true;
0688: }
0689: } else if (result instanceof TracingCollection) {
0690: TracingCollection tracingCollection = (TracingCollection) result;
0691: int[] ops = tracingCollection
0692: .performedOperations();
0693: bypassForDelete = Tracer.Util.isDeleteOnly(ops)
0694: && bypassForDelete;
0695: bypassForInsert = Tracer.Util.isInsertOnly(ops)
0696: && bypassForInsert;
0697: bypassForUpdate = Tracer.Util.isUpdateOnly(ops)
0698: && bypassForUpdate;
0699: bypass = bypassForDelete || bypassForInsert
0700: || bypassForUpdate;
0701: if (!bypass && tracingCollection.dirty()) {
0702: return true;
0703: }
0704: } else if (result instanceof Collection
0705: && !bypassForUpdate) {
0706: Collection collection = (Collection) result;
0707: for (Iterator iterator1 = collection.iterator(); iterator1
0708: .hasNext();) {
0709: Object o1 = iterator1.next();
0710: if (((AbstractPersistentObject) o1).dirty()) {
0711: return true;
0712: }
0713: }
0714: }
0715: }
0716: }
0717: }
0718:
0719: return false;
0720: }
0721:
0722: //
0723: //
0724: // Util classes:
0725: //
0726: //
0727:
0728: /**
0729: * Modify Visitor Type holder
0730: */
0731: public static class ModifyVisitorType {
0732:
0733: private String name;
0734:
0735: public ModifyVisitorType(String name) {
0736: this .name = name;
0737: }
0738:
0739: public static final ModifyVisitorType NULL = new ModifyVisitorType(
0740: "NULL");
0741: public static final ModifyVisitorType INSERT = new ModifyVisitorType(
0742: "INSERT");
0743: public static final ModifyVisitorType UPDATE = new ModifyVisitorType(
0744: "UPDATE");
0745: public static final ModifyVisitorType DELETE = new ModifyVisitorType(
0746: "DELETE");
0747:
0748: public String toString() {
0749: return name;
0750: }
0751:
0752: public static boolean isNullType(Visitor visitor) {
0753: return visitor.getType() == NULL;
0754: }
0755:
0756: public static boolean isInsertType(Visitor visitor) {
0757: return visitor.getType() == INSERT;
0758: }
0759:
0760: public static boolean isUpdateType(Visitor visitor) {
0761: return visitor.getType() == UPDATE;
0762: }
0763:
0764: public static boolean isDeleteType(Visitor visitor) {
0765: return visitor.getType() == DELETE;
0766: }
0767:
0768: public static boolean isInsertOrDelete(Visitor visitor) {
0769: return isInsertType(visitor) || isDeleteType(visitor);
0770: }
0771: }
0772:
0773: /**
0774: * Interface to traverse AbstractPersistentObject trees
0775: */
0776: public static interface Visitor {
0777: /**
0778: *
0779: * @param persistentObject
0780: * @param controller
0781: * @param root set true if persistentObject parameter is the root of traversed tree
0782: * @param complexDirty set true if the object tree is "dirty" in generalized sense
0783: * @return indicator of how many objects are processed
0784: * @throws OdalPersistencyException
0785: */
0786: int visit(AbstractPersistentObject persistentObject,
0787: LifeCycleController controller, boolean root,
0788: boolean complexDirty) throws OdalPersistencyException;
0789:
0790: /**
0791: * @see ModifyVisitorType
0792: *
0793: * @return ModifyVisitorType
0794: */
0795: ModifyVisitorType getType();
0796:
0797: /**
0798: *
0799: * @return root object
0800: */
0801: PersistentObject getRoot();
0802: }
0803:
0804: private static class Context {
0805: private Link currParentLink;
0806: private Link currChildLink;
0807: private LinkedHashMap metaAssemblyMap = new LinkedHashMap();
0808: private Link[] metaAssembly;
0809: }
0810:
0811: private static class ExtraParents {
0812: private LinkedHashMap extraParents; /* LinkedHashMap<Link, List<Link>> */
0813:
0814: public void addExtraParent(Link child, Link extraParent) {
0815: List parents = (List) lazyExtraParents().get(child);
0816: if (parents == null) {
0817: parents = new ArrayList();
0818: lazyExtraParents().put(child, parents);
0819: }
0820: parents.add(extraParent);
0821: }
0822:
0823: private Map lazyExtraParents() {
0824: if (extraParents == null) {
0825: extraParents = new LinkedHashMap();
0826: }
0827: return extraParents;
0828: }
0829:
0830: public List getExtraParents(Link child) {
0831: List result = null;
0832: if (extraParents != null) {
0833: result = (List) extraParents.get(child);
0834: }
0835:
0836: return result == null ? Collections.EMPTY_LIST : result;
0837: }
0838: }
0839:
0840: /**
0841: * Contains Link Assembly Meta data and dataAssemblyMap -
0842: * map of links lists with slink path as a key
0843: */
0844: static class LinkHolder implements Cloneable {
0845:
0846: private LinkedHashMap dataAssemblyMap; /* LinkedHashMap<String, List<Link>> */
0847: private LinkAssemblyMeta meta;
0848:
0849: LinkHolder(Link[] metaAssembly) {
0850: this .meta = new LinkAssemblyMeta(metaAssembly);
0851: setDataAssemblyMap(this );
0852: }
0853:
0854: private LinkHolder() {
0855: }
0856:
0857: private LinkHolder newLinkHolder() {
0858: LinkHolder holder = new LinkHolder();
0859: holder.meta = meta;
0860: setDataAssemblyMap(holder);
0861: return holder;
0862: }
0863:
0864: /**
0865: *
0866: * @return dataAssemblyMap
0867: */
0868: public LinkedHashMap getDataAssemblyMap() {
0869: return dataAssemblyMap;
0870: }
0871:
0872: private void setDataAssemblyMap(LinkHolder holder) {
0873: holder.dataAssemblyMap = meta.newDataAssemblyMap();
0874: }
0875:
0876: /**
0877: * Add Link to dataAssemblyMap
0878: *
0879: * @param linkPath
0880: * @param link
0881: */
0882: public void addLink(String linkPath, Link link) {
0883: if (!link.isAdHoc()) {
0884: List links = (List) dataAssemblyMap.get(linkPath);
0885: if (links == null) {
0886: throw new OdalRuntimePersistencyException(
0887: "Cannot get links by linkPath " + linkPath);
0888: }
0889: links.add(link);
0890: }
0891: }
0892:
0893: /**
0894: *
0895: * @return copy of LinkHolder
0896: * @throws CloneNotSupportedException
0897: */
0898: public Object clone() throws CloneNotSupportedException {
0899: return newLinkHolder();
0900: }
0901:
0902: /**
0903: *
0904: * @return Link assembly meta data
0905: */
0906: public LinkAssemblyMeta getMeta() {
0907: return meta;
0908: }
0909:
0910: /**
0911: *
0912: * @return metaAssemblySize
0913: */
0914: public int metaAssemblySize() {
0915: return meta == null ? 0 : meta.size();
0916: }
0917:
0918: /**
0919: *
0920: * @return true if LinkHolder meta assembly is empty
0921: */
0922: public boolean isMetaAssemblyEmpty() {
0923: return metaAssemblySize() == 0;
0924: }
0925:
0926: /**
0927: *
0928: * @return true if LinkHolder has meta assembly
0929: */
0930: public boolean hasMetaAssembly() {
0931: return !isMetaAssemblyEmpty();
0932: }
0933:
0934: public String toString() {
0935: return super .toString() + "{" + dataAssemblyMap + "}";
0936: }
0937:
0938: public String metaAssemblyToString() {
0939: if (isMetaAssemblyEmpty()) {
0940: return "null";
0941: }
0942: String indent = " ";
0943: StringBuffer buffer = new StringBuffer();
0944: int count = 0;
0945:
0946: for (int i = 0; i < metaAssemblySize(); i++) {
0947: Link key = meta.getLink(i);
0948: buffer.append(indent).append("Final Assembly line[")
0949: .append(++count).append("]; <link> = ").append(
0950: key).append("\n");
0951: }
0952: return buffer.toString();
0953: }
0954:
0955: public Link getMetaAssemblyLink(int index) {
0956: return meta == null ? null : meta.getLink(index);
0957: }
0958: }
0959:
0960: /**
0961: * Link Assembly Meta data. Contains link array and map of links with path as key and
0962: * Link as value
0963: */
0964: static class LinkAssemblyMeta {
0965: private Map metaAssemblyMap;
0966: private Link[] metaAssembly;
0967:
0968: /**
0969: *
0970: * @param metaAssembly
0971: */
0972: public LinkAssemblyMeta(Link[] metaAssembly) {
0973: this .metaAssembly = metaAssembly;
0974: this .metaAssemblyMap = newMetaAssemblyMap(metaAssembly);
0975: }
0976:
0977: private Map newMetaAssemblyMap(Link[] finalAssembly) {
0978: LinkedHashMap finalAssemblyMap = new LinkedHashMap(
0979: finalAssembly.length);
0980: for (int i = 0; i < finalAssembly.length; i++) {
0981: finalAssembly[i].setDependencyIndex(i);
0982: finalAssemblyMap.put(finalAssembly[i].getPathString(),
0983: finalAssembly[i]);
0984: }
0985: return finalAssemblyMap;
0986: }
0987:
0988: public Link getLink(int index) {
0989: return metaAssembly[index];
0990: }
0991:
0992: public Link getLink(String path) {
0993: return (Link) metaAssemblyMap.get(path);
0994: }
0995:
0996: public int size() {
0997: return metaAssembly != null ? metaAssembly.length : 0;
0998: }
0999:
1000: /**
1001: * Creates new Data Assembly Map which has Link path as a key
1002: * and empty List as value. The list gets populated in
1003: * LinkDependencyGraph.addToAssembly() method
1004: *
1005: * @return new Data Assembly Map
1006: */
1007: public LinkedHashMap newDataAssemblyMap() {
1008: LinkedHashMap dataAssemblyMap = new LinkedHashMap(
1009: metaAssembly.length);
1010: for (int i = 0; i < metaAssembly.length; i++) {
1011: dataAssemblyMap.put(metaAssembly[i].getPathString(),
1012: new ArrayList());
1013: }
1014: return dataAssemblyMap;
1015: }
1016:
1017: public String toString() {
1018: return super.toString();
1019: }
1020:
1021: }
1022: }
|