001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.server;
012:
013: import com.versant.core.common.Debug;
014: import com.versant.core.common.OID;
015: import com.versant.core.common.State;
016: import com.versant.core.metadata.ModelMetaData;
017:
018: import java.util.Date;
019: import java.util.Map;
020: import java.util.HashMap;
021:
022: /**
023: * A graph of OID's and State's used to represent a collection of objects
024: * to be persisted. This class implements algorithms to sort the graph
025: * for persisting in the correct order and to detect cycles. This class
026: * only does a partial sort of the graph and is suitable for graphs that
027: * do not contain any new instances with post-insert key generators.
028: */
029: public class PersistGraph extends OIDGraph {
030:
031: protected ModelMetaData jmd;
032: protected OID[] oids;
033: protected State[] oldStates;
034: protected State[] newStates;
035: protected Map oidIndexMap;
036:
037: public boolean optimistic; // Carries this flag for VDS transaction
038:
039: public PersistGraph(ModelMetaData jmd, int maxSize) {
040: this .jmd = jmd;
041: oids = new OID[maxSize];
042: oldStates = new State[maxSize];
043: newStates = new State[maxSize];
044: size = 0;
045: oidIndexMap = new HashMap();
046: }
047:
048: /**
049: * Empty the graph so it can be reused.
050: */
051: public void clear() {
052: for (int i = size - 1; i >= 0; i--) {
053: oids[i] = null;
054: oldStates[i] = null;
055: newStates[i] = null;
056: }
057: size = 0;
058: oidIndexMap.clear();
059: }
060:
061: /**
062: * Add a node to the graph.
063: */
064: public void add(OID oid, State oldState, State newState) {
065: oids[size] = oid;
066: oldStates[size] = oldState;
067: newStates[size] = newState;
068: oidIndexMap.put(oid, new Integer(size++));
069: }
070:
071: /**
072: * How many nodes are in the graph?
073: */
074: public int size() {
075: return size;
076: }
077:
078: /**
079: * Get the OID at index.
080: */
081: public OID getOID(int index) {
082: return oids[index];
083: }
084:
085: /**
086: * Get the old State at index.
087: */
088: public State getOldState(int index) {
089: return oldStates[index];
090: }
091:
092: /**
093: * Get the new State at index.
094: */
095: public State getNewState(int index) {
096: return newStates[index];
097: }
098:
099: /**
100: * Dump the graph to System.out for debugging.
101: */
102: public void dump() {
103: for (int i = 0; i < size; i++)
104: dump(i);
105: }
106:
107: /**
108: * Dump entries at index to System.out for debugging.
109: */
110: public void dump(int index) {
111: if (Debug.DEBUG) {
112: System.out.println("[" + index + "] " + oids[index] + " "
113: + newStates[index]);
114: }
115: }
116:
117: /**
118: * Find the index of OID in the graph or less than 0 if not found.
119: * Calling this method after persist has been called will return incorrect
120: * results.
121: *
122: * @see #indexOfAfterPersist
123: */
124: public int indexOf(OID oid) {
125: Object o = oidIndexMap.get(oid);
126: return o == null ? -1 : ((Integer) o).intValue();
127: }
128:
129: /**
130: * Find the index of OID in the graph or less than 0 if not found.
131: * This method may be called after persist has been called. It will
132: * build the OID to index map the first time it is called.
133: *
134: * @see #indexOf
135: */
136: public int indexOfAfterPersist(OID oid) {
137: if (oidIndexMap.size() == 0) {
138: OID[] oids = this .oids;
139: for (int i = size - 1; i >= 0; i--) {
140: oidIndexMap.put(oids[i], new Integer(i));
141: }
142: }
143: Object o = oidIndexMap.get(oid);
144: return o == null ? -1 : ((Integer) o).intValue();
145: }
146:
147: /**
148: * Bump up timestamps etc.
149: */
150: public void doAutoSets() {
151: Date now = new Date();
152: for (int i = 0; i < size; i++) {
153: OID oid = oids[i];
154: State ns = newStates[i];
155: if (ns == null)
156: break;
157: ns.setClassMetaData(oid.getClassMetaData());
158: if (oid.isNew()) {
159: ns.updateAutoSetFieldsCreated(now);
160: } else {
161: ns.updateAutoSetFieldsModified(now, oldStates[i]);
162: }
163: }
164: }
165:
166: /**
167: * Compare graph entries at and a and b. Return 0 if equal, less than 0
168: * if a is less than b or greater than 0 if a is greater than b. This
169: * orders entries by class referenceGraphIndex, by new objects first,
170: * by field numbers.
171: */
172: protected int compare(int a, int b) {
173: final OID oidA = oids[a];
174: final OID oidB = oids[b];
175:
176: int diff = oidB.getClassMetaData().referenceGraphIndex
177: - oidA.getClassMetaData().referenceGraphIndex;
178: if (diff != 0)
179: return diff;
180:
181: // by new objects
182: boolean newA = oidA.isNew();
183: boolean newB = oidB.isNew();
184: if (newA && !newB)
185: return -1;
186: if (!newA && newB)
187: return +1;
188:
189: // by field numbers
190: return newStates[a].compareToPass1(newStates[b]);
191: }
192:
193: /**
194: * Swap entries.
195: */
196: protected void swap(int index1, int index2) {
197: OID tempStr = oids[index1];
198: State tempOldState = oldStates[index1];
199: State tempNewState = newStates[index1];
200:
201: oids[index1] = oids[index2];
202: oldStates[index1] = oldStates[index2];
203: newStates[index1] = newStates[index2];
204:
205: oids[index2] = tempStr;
206: oldStates[index2] = tempOldState;
207: newStates[index2] = tempNewState;
208: }
209: }
|