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.LinkIterator;
0012: import com.completex.objective.util.PropertyMap;
0013:
0014: import java.io.Serializable;
0015: import java.util.ArrayList;
0016: import java.util.Arrays;
0017: import java.util.Collection;
0018: import java.util.HashMap;
0019: import java.util.HashSet;
0020: import java.util.Iterator;
0021: import java.util.LinkedHashMap;
0022: import java.util.LinkedList;
0023: import java.util.List;
0024: import java.util.Map;
0025: import java.util.Set;
0026:
0027: /**
0028: * Represents tree structure used to create Query trees as well as PersistentObject trees.
0029: *
0030: * @author Gennady Krizhevsky
0031: */
0032: public class Link extends ParentBase implements Parent, Serializable,
0033: Cloneable, Mappable {
0034: static final long serialVersionUID = 1L;
0035: public static final String SEP = "|";
0036:
0037: private transient Query query;
0038: private transient LifeCycleController lifeCycleController;
0039: protected transient int[] parentIndeces;
0040: protected transient int[] this Indeces;
0041: private transient boolean lazyRetrieval;
0042: private transient boolean insertBeforeParent; /* it means also "update Before Parent" & "delete After Parent" */
0043: private transient boolean cascadeDelete;
0044: private transient boolean cascadeInsert;
0045: private transient boolean cascadeUpdate;
0046: private transient boolean treatNullAsRemove;
0047: private transient int dependencyIndex = -1;
0048: protected transient InlineMode inlineMode;
0049: private transient boolean retrieved;
0050: private transient boolean adHoc;
0051:
0052: private boolean endOfChain;
0053: private Object result;
0054: private String name;
0055: // Meta data:
0056: private List path = new LinkedList();
0057: private static final String TAG_PARENT_INDECES = "parentIndeces";
0058: private static final String TAG_THIS_INDECES = "thisIndeces";
0059: private static final String TAG_NAME = "name";
0060: public static final String TAG_QUERY = "query";
0061: public static final String TAG_QUERY_CLASS = "queryClass";
0062:
0063: public Link() {
0064: }
0065:
0066: public Link(Map map) {
0067: fromMap(map);
0068: }
0069:
0070: public Link(String name) {
0071: setName(name);
0072: }
0073:
0074: public Link(String name, Object result) {
0075: this .name = name;
0076: this .result = result;
0077: }
0078:
0079: public Link(String name, Object result, boolean adHoc) {
0080: this .name = name;
0081: this .result = result;
0082: this .adHoc = adHoc;
0083: }
0084:
0085: /**
0086: * @param query Query object
0087: * @param parentIndeces parent indeces which values are mapped to corresponding "this indeces"
0088: * @param thisIndeces "this indeces" indeces which values are mapped to corresponding parent ones
0089: */
0090: public Link(Query query, int[] parentIndeces, int this Indeces[]) {
0091: this (query, parentIndeces, this Indeces, null);
0092: }
0093:
0094: /**
0095: * @param query Query object
0096: * @param parentIndeces parent indeces which values are mapped to corresponding "this indeces"
0097: * @param thisIndeces "this indeces" indeces of this link query's SingularResultFactory
0098: * which values are mapped to corresponding parent ones
0099: * @param name link name - mandatory for PersistentObject trees
0100: */
0101: public Link(Query query, int[] parentIndeces, int this Indeces[],
0102: String name) {
0103: this .query = query;
0104: this .parentIndeces = parentIndeces;
0105: this .name = name;
0106: if (parentIndeces == null) {
0107: addToPath(getName());
0108: } else {
0109: if (this Indeces == null) {
0110: throw new IllegalArgumentException(
0111: "thisIndeces == null");
0112: }
0113: if (this Indeces.length != parentIndeces.length) {
0114: throw new IllegalArgumentException(
0115: "thisIndeces.length != parentIndeces.length");
0116: }
0117: this .this Indeces = this Indeces;
0118: }
0119: }
0120:
0121: public Link(Link source) {
0122: this (source.query, source.parentIndeces, source.this Indeces,
0123: source.name);
0124: }
0125:
0126: public Link copyAll(Link source) {
0127: this .query = source.query;
0128: this .lifeCycleController = source.lifeCycleController;
0129: this .parentIndeces = source.parentIndeces;
0130: this .this Indeces = source.this Indeces;
0131: this .lazyRetrieval = source.lazyRetrieval;
0132: this .insertBeforeParent = source.insertBeforeParent;
0133: this .cascadeDelete = source.cascadeDelete;
0134: this .cascadeInsert = source.cascadeInsert;
0135: this .cascadeUpdate = source.cascadeUpdate;
0136: this .treatNullAsRemove = source.treatNullAsRemove;
0137: this .dependencyIndex = source.dependencyIndex;
0138: this .inlineMode = source.inlineMode;
0139: this .endOfChain = source.endOfChain;
0140: this .result = source.result;
0141: this .name = source.name;
0142: this .path = source.path;
0143: return this ;
0144: }
0145:
0146: /**
0147: * Returns itself
0148: *
0149: * @return itself
0150: */
0151: public Link toLink() {
0152: return this ;
0153: }
0154:
0155: /**
0156: * Sets cascadeDelete = true; cascadeInsert = true; cascadeUpdate = true. Values are used in
0157: * PersistentObject trees
0158: *
0159: * @return itself
0160: */
0161: public Link setCascadeAll() {
0162: cascadeDelete = true;
0163: cascadeInsert = true;
0164: cascadeUpdate = true;
0165: return this ;
0166: }
0167:
0168: /**
0169: * Unsets cascadeDelete = true; cascadeInsert = true; cascadeUpdate = true. Values are used in
0170: * PersistentObject trees
0171: *
0172: * @return itself
0173: */
0174: public Link unsetCascadeAll() {
0175: cascadeDelete = false;
0176: cascadeInsert = false;
0177: cascadeUpdate = false;
0178: return this ;
0179: }
0180:
0181: /**
0182: * Sets setRelationship to parent
0183: *
0184: * @param relationshipType
0185: * @see RelationshipType
0186: */
0187: public void setRelationshipToParent(
0188: RelationshipType relationshipType) {
0189: if (MANY_TO_ONE.equals(relationshipType)) {
0190: insertBeforeParent = true;
0191: }
0192: }
0193:
0194: /**
0195: * Returns LifeCycleController set for this link
0196: *
0197: * @return LifeCycleController set for this link
0198: */
0199: public LifeCycleController getLifeCycleController() {
0200: return lifeCycleController;
0201: }
0202:
0203: /**
0204: * Sets LifeCycleController for this link
0205: *
0206: * @param lifeCycleController
0207: */
0208:
0209: public void setLifeCycleController(
0210: LifeCycleController lifeCycleController) {
0211: this .lifeCycleController = lifeCycleController;
0212: }
0213:
0214: /**
0215: * Sets link name. Link name is mandatory for PersistentObject trees
0216: *
0217: * @param name link name
0218: */
0219: public void setName(String name) {
0220: this .name = name;
0221: }
0222:
0223: /**
0224: * Returns link name
0225: *
0226: * @return link name
0227: */
0228: public String getName() {
0229: return name;
0230: }
0231:
0232: /**
0233: * Returns true is this link is end of link chain. Marking link as end of chain prevents
0234: * infinite loops of retrievals when circular link references are set.
0235: *
0236: * @return true is this link is end of link chain
0237: */
0238: public boolean isEndOfChain() {
0239: return endOfChain;
0240: }
0241:
0242: /**
0243: * If true - this link is end of link chain. Marking link as end of chain prevents
0244: * infinite loops of retrievals when circular link references are set.
0245: *
0246: * @param endOfChain true is this link is end of link chain
0247: */
0248: public void setEndOfChain(boolean endOfChain) {
0249: this .endOfChain = endOfChain;
0250: }
0251:
0252: /**
0253: * Returns link dependency index
0254: *
0255: * @return link dependency index
0256: */
0257: public int getDependencyIndex() {
0258: return dependencyIndex;
0259: }
0260:
0261: /**
0262: * Sets link dependency index
0263: *
0264: * @param dependencyIndex link dependency index
0265: */
0266: public void setDependencyIndex(int dependencyIndex) {
0267: this .dependencyIndex = dependencyIndex;
0268: }
0269:
0270: /**
0271: * Returns "this indeces" - indeces of this link query's SingularResultFactory
0272: * which values are mapped to corresponding parent ones. Usually they are foregn key ones
0273: *
0274: * @return "this indeces" - indeces of this link query's SingularResultFactory
0275: * which values are mapped to corresponding parent ones
0276: */
0277: public int[] getThisIndeces() {
0278: return this Indeces;
0279: }
0280:
0281: /**
0282: * Sets "this indeces" - indeces of this link query's SingularResultFactory
0283: * which values are mapped to corresponding parent ones. Usually they are foregn key ones
0284: *
0285: * @param thisIndeces "this indeces" - indeces of this link query's SingularResultFactory
0286: * which values are mapped to corresponding parent ones
0287: */
0288: public void setThisIndeces(int[] this Indeces) {
0289: this .this Indeces = this Indeces;
0290: }
0291:
0292: /**
0293: * Returns parent indeces - indeces of the parent persistent object which contains a link [pointing to itself.
0294: * Usually they are the primary key ones.
0295: *
0296: * @return parent indeces - indeces of the parent persistent object which contains a link [pointing to itself.
0297: * Usually they are the primary key ones.
0298: */
0299: public int[] getParentIndeces() {
0300: return parentIndeces;
0301: }
0302:
0303: /**
0304: * Sets parent indeces - indeces of the parent persistent object which contains a link [pointing to itself.
0305: * Usually they are the primary key ones.
0306: *
0307: * @param parentIndeces indeces of the parent persistent object which contains a link [pointing to itself.
0308: * Usually they are the primary key ones.
0309: */
0310: public void setParentIndeces(int[] parentIndeces) {
0311: this .parentIndeces = parentIndeces;
0312: }
0313:
0314: /**
0315: * Returns full path to this link built of the names of the parent chain
0316: *
0317: * @return full path to this link built of the names of the parent chain
0318: */
0319: public String getPathString() {
0320: StringBuffer buffer = new StringBuffer();
0321: for (int i = 0; i < path.size(); i++) {
0322: buffer.append(path.get(i));
0323: if (i < path.size() - 1) {
0324: buffer.append(SEP);
0325: }
0326: }
0327: return buffer.toString();
0328: }
0329:
0330: public void setPath(String pathString) {
0331: path = string2path(pathString);
0332: }
0333:
0334: public static String path2string(List path) {
0335: StringBuffer buffer = new StringBuffer();
0336: for (int i = 0; i < path.size(); i++) {
0337: buffer.append(path.get(i));
0338: if (i < path.size() - 1) {
0339: buffer.append(SEP);
0340: }
0341: }
0342: return buffer.toString();
0343: }
0344:
0345: public static List string2path(String pathString) {
0346: String[] tokens = pathString.split(SEP);
0347: ArrayList path = new ArrayList(tokens.length);
0348: for (int i = 0; i < path.size(); i++) {
0349: path.add(tokens[i]);
0350: }
0351: return path;
0352: }
0353:
0354: /**
0355: * Sets full path to this link built of the names of the parent chain
0356: *
0357: * @param path full path to this link built of the names of the parent chain
0358: */
0359: void setPath(List path) {
0360: this .path = path;
0361: }
0362:
0363: /**
0364: * Returns full path to this link built of the names of the parent chain
0365: *
0366: * @return full path to this link built of the names of the parent chain
0367: */
0368: public List getPath() {
0369: return path;
0370: }
0371:
0372: /**
0373: * Appends all of the elements in the specified parentPath to the end of
0374: * this link's path
0375: *
0376: * @param parentPath to append to the end of
0377: * this link's path
0378: */
0379: public void addParentPath(List parentPath) {
0380: if (parentPath != null) {
0381: for (int i = 0; i < parentPath.size(); i++) {
0382: String parentName = (String) parentPath.get(i);
0383: addToPath0(parentName);
0384: }
0385: }
0386: }
0387:
0388: /**
0389: * Adds name to this link's path
0390: *
0391: * @param name to add
0392: */
0393: public void addToPath(String name) {
0394: addToPath0(name);
0395: setName(name);
0396: }
0397:
0398: private void addToPath0(String name) {
0399: if (path.size() > 0) {
0400: String lastName = (String) path.get(path.size() - 1);
0401: if (lastName.equals(name)) {
0402: throw new IllegalArgumentException(
0403: "Attempt to add name twice");
0404: }
0405: } else if (!ROOT.equals(name)) {
0406: path.add(ROOT);
0407: }
0408: if (name != null) {
0409: path.add(name);
0410: }
0411: }
0412:
0413: /**
0414: * Returns result - data that is set during query execution for selects
0415: * or by using setter methods for update operations
0416: *
0417: * @return result - data that is set during query execution for selects
0418: * or by using setter methods for update operations
0419: */
0420: public Object getResult() {
0421: return result;
0422: }
0423:
0424: public Collection getResultAsCollection() {
0425: return (Collection) result;
0426: }
0427:
0428: public void addToResultCollection(Object value) {
0429: getResultAsCollection().add(value);
0430: }
0431:
0432: public void addNotNullToResultCollection(Object value) {
0433: if (value != null) {
0434: getResultAsCollection().add(value);
0435: }
0436: }
0437:
0438: /**
0439: * Sets result - data that is set during query execution for selects
0440: * or by using setter methods for update operations
0441: *
0442: * @param result data that is set during query execution for selects
0443: * or by using setter methods for update operations
0444: */
0445: public void setResult(Object result) {
0446: this .result = result;
0447: }
0448:
0449: /**
0450: * Returns query that is used to retrieve object trees
0451: *
0452: * @return query that is used to retrieve object trees
0453: */
0454: public Query getQuery() {
0455: return query;
0456: }
0457:
0458: /**
0459: * Sets query that is used to retrieve object trees
0460: *
0461: * @param query query that is used to retrieve object trees
0462: */
0463: public void setQuery(Query query) {
0464: this .query = query;
0465: }
0466:
0467: /**
0468: * Returns true the result of this link has to be performed in "lazy" fashion
0469: *
0470: * @return true the result of this link has to be performed in "lazy" fashion
0471: */
0472: public boolean isLazyRetrieval() {
0473: return lazyRetrieval;
0474: }
0475:
0476: /**
0477: * Sets true the result of this link has to be performed in "lazy" fashion
0478: *
0479: * @param lazyRetrieval true the result of this link has to be performed in "lazy" fashion
0480: */
0481: public void setLazyRetrieval(boolean lazyRetrieval) {
0482: this .lazyRetrieval = lazyRetrieval;
0483: }
0484:
0485: /**
0486: * Returns true if the result (data) of this link is to be inserted before the parent link's one
0487: *
0488: * @return true if the result (data) of this link is to be inserted before the parent link's one
0489: */
0490: public boolean isInsertBeforeParent() {
0491: return insertBeforeParent;
0492: }
0493:
0494: /**
0495: * Sets true if the result (data) of this link is to be inserted before the parent link's one
0496: *
0497: * @param insertBeforeParent true if the result (data) of this link is to be inserted before the parent link's one
0498: */
0499: public void setInsertBeforeParent(boolean insertBeforeParent) {
0500: this .insertBeforeParent = insertBeforeParent;
0501: }
0502:
0503: /**
0504: * Returns true if for one-to-one inversed relationship
0505: * (this link contains foreign key object and its child contains the primary key ones)
0506: * nullifying the foregn key field should cause deletion of the child object
0507: *
0508: *
0509: * @return true if for one-to-one inversed relationship
0510: * (this link contains foreign key object and its child contains the primary key ones)
0511: * nullifying the foregn key field should cause deletion of the child object
0512: */
0513: public boolean isTreatNullAsRemove() {
0514: return treatNullAsRemove;
0515: }
0516:
0517: /**
0518: * Sets true if for one-to-one inversed relationship
0519: * (this link contains foreign key object and its child contains the primary key ones)
0520: * nullifying the foregn key field should cause deletion of the child object
0521: *
0522: * @param treatNullAsRemove true if for one-to-one inversed relationship
0523: * (this link contains foreign key object and its child contains the primary key ones)
0524: * nullifying the foregn key field should cause deletion of the child object
0525: */
0526: public void setTreatNullAsRemove(boolean treatNullAsRemove) {
0527: this .treatNullAsRemove = treatNullAsRemove;
0528: }
0529:
0530: /**
0531: * Returns true if delete is to be propagated to this link when the parent one gets deleted
0532: *
0533: * @return true if delete is to be propagated to this link when the parent one gets deleted
0534: */
0535: public boolean isCascadeDelete() {
0536: return cascadeDelete;
0537: }
0538:
0539: /**
0540: * Sets true if delete is to be propagated to this link when the parent one gets deleted
0541: *
0542: * @param cascadeDelete true if delete is to be propagated to this link when the parent one gets deleted
0543: */
0544: public void setCascadeDelete(boolean cascadeDelete) {
0545: this .cascadeDelete = cascadeDelete;
0546: }
0547:
0548: /**
0549: * Returns true if delete is to be propagated to this link when the parent one gets inserted
0550: *
0551: * @return true if delete is to be propagated to this link when the parent one gets inserted
0552: */
0553: public boolean isCascadeInsert() {
0554: return cascadeInsert;
0555: }
0556:
0557: /**
0558: * Sets true if delete is to be propagated to this link when the parent one gets inserted
0559: *
0560: * @param cascadeInsert true if delete is to be propagated to this link when the parent one gets inserted
0561: */
0562: public void setCascadeInsert(boolean cascadeInsert) {
0563: this .cascadeInsert = cascadeInsert;
0564: }
0565:
0566: /**
0567: * Returns true if delete is to be propagated to this link when the parent one gets updated
0568: *
0569: * @return true if delete is to be propagated to this link when the parent one gets updated
0570: */
0571: public boolean isCascadeUpdate() {
0572: return cascadeUpdate;
0573: }
0574:
0575: /**
0576: * Sets true if delete is to be propagated to this link when the parent one gets updated
0577: *
0578: * @param cascadeUpdate true if delete is to be propagated to this link when the parent one gets updated
0579: */
0580: public void setCascadeUpdate(boolean cascadeUpdate) {
0581: this .cascadeUpdate = cascadeUpdate;
0582: }
0583:
0584: /**
0585: * Experimental
0586: */
0587: public boolean isInline() {
0588: return inlineMode != null;
0589: }
0590:
0591: /**
0592: * Experimental
0593: */
0594: public InlineMode getInlineMode() {
0595: return inlineMode;
0596: }
0597:
0598: /**
0599: * Experimental
0600: */
0601: public void setInlineMode(InlineMode inlineMode) {
0602: this .inlineMode = inlineMode;
0603: }
0604:
0605: /**
0606: * Returns new instance of this link that inherits set of its parent properties
0607: *
0608: * @return new instance of this link that inherits set of its parent properties
0609: */
0610: public Link newInstance() {
0611: Query query = null;
0612: if (this .query != null) {
0613: query = this .query.newQuery();
0614: }
0615: Link link = newInstance0(query);
0616: link.setName(name);
0617: link.setPath(path);
0618: link.setLazyRetrieval(lazyRetrieval);
0619: link.setInsertBeforeParent(insertBeforeParent);
0620: link.setDependencyIndex(dependencyIndex);
0621: link.setCascadeDelete(cascadeDelete);
0622: link.setCascadeInsert(cascadeInsert);
0623: link.setCascadeUpdate(cascadeUpdate);
0624: link.setTreatNullAsRemove(treatNullAsRemove);
0625: link.setEndOfChain(endOfChain);
0626: if (lifeCycleController != null) {
0627: link.setLifeCycleController(lifeCycleController
0628: .newLifeCycleInstance());
0629: }
0630: link.path = cloneList(path);
0631: return link;
0632: }
0633:
0634: List cloneList(List list) {
0635: if (list instanceof LinkedList) {
0636: return (List) ((LinkedList) list).clone();
0637: } else if (list instanceof ArrayList) {
0638: return (List) ((ArrayList) list).clone();
0639: } else {
0640: throw new RuntimeException("Unsupported type " + list);
0641: }
0642: }
0643:
0644: protected Link newInstance0(Query query) {
0645: return new Link(query, parentIndeces, this Indeces);
0646: }
0647:
0648: /**
0649: * Returns Deep copy of this link
0650: *
0651: * @return Deep copy of this link
0652: * @throws CloneNotSupportedException
0653: */
0654: public Object clone() throws CloneNotSupportedException {
0655: Link link = (Link) super .clone();
0656: Object result = link.getResult();
0657: Object clonedResult = link.getResult();
0658: if (query != null) {
0659: link.setQuery(((Query) query.clone()));
0660: }
0661: if (result != null) {
0662: if (result instanceof com.completex.objective.components.persistency.Cloneable) {
0663: clonedResult = ((com.completex.objective.components.persistency.Cloneable) result)
0664: .clone();
0665: } else if (result instanceof LinkedList) {
0666: clonedResult = ((LinkedList) result).clone();
0667: populateClonedCollection(((List) clonedResult));
0668: } else if (result instanceof ArrayList) {
0669: clonedResult = ((ArrayList) result).clone();
0670: populateClonedCollection(((List) clonedResult));
0671: } else if (result instanceof HashSet) {
0672: clonedResult = ((HashSet) result).clone();
0673: populateClonedCollection(((Set) clonedResult));
0674: } else if (result instanceof HashMap) {
0675: clonedResult = ((HashMap) result).clone();
0676: populateClonedMap(((Map) clonedResult));
0677: }
0678: }
0679: link.setResult(clonedResult);
0680: if (link.hasChildren()) {
0681: for (LinkIterator it = linkIterator(); it.hasNext();) {
0682: Link child = it.nextLink();
0683: child.clone();
0684: }
0685: }
0686: link.inlineMode = inlineMode;
0687: return link;
0688: }
0689:
0690: public void populateClonedCollection(Collection collection) {
0691: if (collection == null) {
0692: return;
0693: }
0694: AbstractPersistentObject[] objects = (AbstractPersistentObject[]) collection
0695: .toArray(new AbstractPersistentObject[collection.size()]);
0696: for (int i = 0; i < objects.length; i++) {
0697: AbstractPersistentObject object = objects[i];
0698: if (objects[i] != null) {
0699: objects[i] = (AbstractPersistentObject) object.clone();
0700: }
0701: }
0702: collection.clear();
0703: collection.addAll(Arrays.asList(objects));
0704:
0705: }
0706:
0707: public void populateClonedMap(Map map) {
0708: if (map == null) {
0709: return;
0710: }
0711: for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
0712: Map.Entry entry = (Map.Entry) it.next();
0713: Object value = entry.getValue();
0714: if (value instanceof AbstractPersistentObject) {
0715: entry.setValue(((AbstractPersistentObject) value)
0716: .clone());
0717: }
0718: }
0719:
0720: }
0721:
0722: /**
0723: * Copies results from "from" link to this one without touching children
0724: *
0725: * @param from
0726: */
0727: public void copyResultsOneLevel(Link from) {
0728: copyResultsOneLevel(from, this );
0729: }
0730:
0731: /**
0732: * Copies results from "from" link to this one including children
0733: *
0734: * @param from
0735: */
0736: public void copyResults(Link from) {
0737: copyResults(from, this , 0);
0738: }
0739:
0740: private static void copyResultsOneLevel(Link from, Link to) {
0741: if (from == null || to == null) {
0742: return;
0743: }
0744:
0745: if (from.getResult() != null) {
0746: to.setResult(from.getResult());
0747: }
0748:
0749: }
0750:
0751: // Copy results from parameter to this:
0752: public static void copyResults(Link from, Link to, int level) {
0753: level++;
0754: if (from == null || to == null) {
0755: return;
0756: }
0757:
0758: if (from.getResult() != null) {
0759: to.setResult(from.getResult());
0760: }
0761:
0762: LinkedHashMap toChildren = to.getChildren();
0763: if (toChildren != null) {
0764: for (LinkIterator it = from.linkIterator(); it.hasNext();) {
0765: Link fromChild = it.nextLink();
0766: String name = fromChild.getName();
0767: Link toChild = (Link) toChildren.get(name);
0768: if (toChild != null) {
0769: copyResults(fromChild, toChild, level);
0770: } else {
0771: // case when ad-hoc results are added:
0772: fromChild.setAdHoc(true);
0773: toChildren.put(name, fromChild);
0774: }
0775: }
0776: }
0777: }
0778:
0779: public boolean isAdHoc() {
0780: return adHoc;
0781: }
0782:
0783: public void setAdHoc(boolean adHoc) {
0784: this .adHoc = adHoc;
0785: }
0786:
0787: public boolean isRetrieved() {
0788: return retrieved;
0789: }
0790:
0791: public void setRetrieved(boolean retrieved) {
0792: this .retrieved = retrieved;
0793: }
0794:
0795: public Map toMap() {
0796: Map map = super .toMap();
0797: toMapArray(map, TAG_PARENT_INDECES, parentIndeces);
0798: toMapArray(map, TAG_THIS_INDECES, this Indeces);
0799: map.put(TAG_NAME, name);
0800: if (query != null) {
0801: map.put(TAG_QUERY, ((Mappable) query).toMap());
0802: map.put(TAG_QUERY_CLASS, query.getClass().getName());
0803: }
0804:
0805: return map;
0806: }
0807:
0808: public void fromMap(Map map) {
0809: super .fromMap(map);
0810: PropertyMap propertyMap = PropertyMap.toPropertyMap(map);
0811: parentIndeces = fromMapToIntArray(propertyMap,
0812: TAG_PARENT_INDECES);
0813: this Indeces = fromMapToIntArray(propertyMap, TAG_THIS_INDECES);
0814: name = propertyMap.getProperty(TAG_NAME);
0815: Map queryMap = propertyMap.getMap(TAG_QUERY);
0816: if (queryMap != null) {
0817: String queryClassName = propertyMap.getProperty(
0818: TAG_QUERY_CLASS, true);
0819: try {
0820: query = (Query) Class.forName(queryClassName)
0821: .newInstance();
0822: } catch (Exception e) {
0823: throw new OdalRuntimePersistencyException(
0824: "Cannot instantiate class by name "
0825: + queryClassName, e);
0826: }
0827: ((Mappable) query).fromMap(queryMap);
0828: }
0829: }
0830:
0831: protected void toMapArray(Map map, String tag, int[] array) {
0832: if (array != null) {
0833: String[] arrayS = new String[array.length];
0834: for (int i = 0; i < array.length; i++) {
0835: arrayS[i] = String.valueOf(array[i]);
0836: }
0837: map.put(tag, Arrays.asList(arrayS));
0838: }
0839: }
0840:
0841: protected int[] fromMapToIntArray(PropertyMap map, String tag) {
0842: int[] array = null;
0843: List list = map.getList(tag);
0844: if (list != null) {
0845: array = new int[list.size()];
0846: for (int i = 0; i < list.size(); i++) {
0847: String value = (String) list.get(i);
0848: int intValue = 0;
0849: if (value != null) {
0850: intValue = Integer.parseInt(value);
0851: }
0852: array[i] = intValue;
0853: }
0854: }
0855: return array;
0856: }
0857:
0858: public String toString() {
0859: StringBuffer buffer = new StringBuffer(" Link : {");
0860: buffer.append("name = ").append(name);
0861: buffer.append(parentIndecesBuffer());
0862: buffer.append("; dependencyIndex = (").append(dependencyIndex)
0863: .append(")");
0864: buffer.append("; path = ").append(getPathString());
0865: buffer.append("; parent path = ");
0866:
0867: StringBuffer parentIndecesBuffer = new StringBuffer(
0868: "; parentIndeces [");
0869: if (parentIndeces != null) {
0870: for (int i = 0; i < parentIndeces.length; i++) {
0871: if (i > 0) {
0872: parentIndecesBuffer.append(", ");
0873: }
0874: parentIndecesBuffer.append(parentIndeces[i]);
0875: }
0876: } else {
0877: parentIndecesBuffer.append("null");
0878: }
0879: parentIndecesBuffer.append("]");
0880:
0881: if (getParentLink() != null) {
0882: buffer.append(getParentLink().getPathString());
0883: } else {
0884: buffer.append("null");
0885: }
0886: buffer.append("; result = (").append(result).append(")");
0887: buffer.append("}");
0888: return super .toString() + buffer.toString();
0889: }
0890:
0891: /**
0892: * Returns summary string
0893: *
0894: * @return summary string
0895: */
0896: public String toSummaryString() {
0897: StringBuffer buffer = new StringBuffer(" Link<");
0898: buffer.append("name = ").append(name);
0899: buffer.append(parentIndecesBuffer()).append(">");
0900: return super .toString() + buffer.toString();
0901: }
0902:
0903: private StringBuffer parentIndecesBuffer() {
0904: StringBuffer parentIndecesBuffer = new StringBuffer(
0905: "; parentIndeces [");
0906: if (parentIndeces != null) {
0907: for (int i = 0; i < parentIndeces.length; i++) {
0908: if (i > 0) {
0909: parentIndecesBuffer.append(", ");
0910: }
0911: parentIndecesBuffer.append(parentIndeces[i]);
0912: }
0913: } else {
0914: parentIndecesBuffer.append("null");
0915: }
0916: parentIndecesBuffer.append("]");
0917: return parentIndecesBuffer;
0918: }
0919:
0920: public static final RelationshipType ONE_TO_MANY = RelationshipType.ONE_TO_MANY;
0921: public static final RelationshipType ONE_TO_ONE = RelationshipType.ONE_TO_ONE;
0922: public static final RelationshipType MANY_TO_ONE = RelationshipType.MANY_TO_ONE;
0923: public static final RelationshipType MANY_TO_MANY = RelationshipType.MANY_TO_MANY;
0924:
0925: public static final String INLINE_INNER = "inner";
0926: public static final String INLINE_OUTER = "outer";
0927: /**
0928: * Inner (or equi-) join mode:
0929: */
0930: public static final InlineMode INNER_JOIN_MODE = new InlineMode(
0931: INLINE_INNER);
0932:
0933: /**
0934: * Outer (left outer) join mode
0935: */
0936: public static final InlineMode OUTER_JOIN_MODE = new InlineMode(
0937: INLINE_OUTER);
0938:
0939: public static InlineMode toInlineMode(String modeName) {
0940: if (INLINE_INNER.equalsIgnoreCase(modeName)) {
0941: return INNER_JOIN_MODE;
0942: } else if (INLINE_OUTER.equalsIgnoreCase(modeName)) {
0943: return OUTER_JOIN_MODE;
0944: } else {
0945: throw new IllegalArgumentException(
0946: "Unknown inline mode name: " + modeName);
0947: }
0948: }
0949:
0950: public boolean isInner() {
0951: return getInlineMode() == INNER_JOIN_MODE;
0952: }
0953:
0954: public boolean isOuter() {
0955: return getInlineMode() == OUTER_JOIN_MODE;
0956: }
0957:
0958: public void setInlineMode(String childName, InlineMode inlineMode) {
0959: getChild(childName).setInlineMode(inlineMode);
0960: }
0961:
0962: /**
0963: * Represents entities relationship in ER paradigm
0964: */
0965: public static class RelationshipType {
0966:
0967: public static final RelationshipType ONE_TO_MANY = new RelationshipType(
0968: "one_to_many");
0969: public static final RelationshipType ONE_TO_ONE = new RelationshipType(
0970: "one_to_one");
0971: public static final RelationshipType MANY_TO_ONE = new RelationshipType(
0972: "many_to_one");
0973: public static final RelationshipType MANY_TO_MANY = new RelationshipType(
0974: "many_to_many");
0975:
0976: private String name;
0977:
0978: protected RelationshipType(String name) {
0979: this .name = name;
0980: }
0981:
0982: public String toString() {
0983: return name;
0984: }
0985:
0986: public String getName() {
0987: return name;
0988: }
0989:
0990: public static RelationshipType name2type(String name) {
0991: if (ONE_TO_MANY.getName().equals(name)) {
0992: return ONE_TO_MANY;
0993:
0994: } else if (ONE_TO_ONE.getName().equals(name)) {
0995: return ONE_TO_ONE;
0996:
0997: } else if (MANY_TO_ONE.getName().equals(name)) {
0998: return MANY_TO_ONE;
0999: } else {
1000: throw new UnsupportedOperationException(name);
1001: }
1002: }
1003: }
1004:
1005: /**
1006: * Represents query inlining mode. Inlined queries are executed in the same SQL statement
1007: * as the main query.
1008: */
1009: public static class InlineMode {
1010:
1011: private String name;
1012:
1013: protected InlineMode(String name) {
1014: this .name = name;
1015: }
1016:
1017: public String toString() {
1018: return name;
1019: }
1020: }
1021: }
|