KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > versant > core > jdo > DetachStateContainer


1
2 /*
3  * Copyright (c) 1998 - 2005 Versant Corporation
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  * Versant Corporation - initial API and implementation
11  */

12 package com.versant.core.jdo;
13
14 import com.versant.core.jdo.sco.*;
15 import com.versant.core.jdo.sco.detached.DetachSCOFactoryRegistry;
16 import com.versant.core.metadata.*;
17 import com.versant.core.common.OID;
18 import com.versant.core.common.State;
19 import com.versant.core.common.*;
20
21 import javax.jdo.spi.JDOImplHelper;
22 import javax.jdo.spi.PersistenceCapable;
23 import java.lang.reflect.Array JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.Map JavaDoc;
26
27 /**
28  * This keeps track of State's, FetchGroup's, OID's and PCs for the detach
29  * code. It provides a list of State's and FetchGroup's for a breadth first
30  * traversal of a State graph. It also provides hashed access to the State
31  * and PC for a given OID.
32  */

33 public class DetachStateContainer {
34
35     private static final int INITIAL_SIZE = 16;
36     private final JDOImplHelper jdoImplHelper = JDOImplHelper.getInstance();
37
38     private int size;
39     private int sizeFG;
40     private int sizeRefs;
41     private int capacity = INITIAL_SIZE;
42     private int capacityFG = INITIAL_SIZE;
43     private int capacityRefs = INITIAL_SIZE * 2;
44     private int posFG = -1;
45
46     private State[] states = new State[capacity];
47     private PersistenceCapable[] pcs = new PersistenceCapable[capacity];
48     private OID[] oids = new OID[capacity];
49     private FetchGroup[][] stateFG = new FetchGroup[capacity][];
50     private FetchGroup[] fetchGroups = new FetchGroup[capacityFG];
51     private int[] stateIndexs = new int[capacityFG];
52     private State[] stateRefs = new State[capacityRefs];
53     private Map JavaDoc oidMap = new HashMap JavaDoc();
54
55     private final VersantDetachStateManager stateManager = new VersantDetachStateManager();
56     private final VersantDetachedStateManager detachedStateManager = new VersantDetachedStateManager();
57     private final VersantPersistenceManagerImp pm;
58     private final DetachSCOFactoryRegistry scoFactoryRegistry = new DetachSCOFactoryRegistry();
59     private final ModelMetaData modelMetaData;
60
61     public DetachStateContainer(VersantPersistenceManagerImp pm) {
62         this.pm = pm;
63         modelMetaData = pm.modelMetaData;
64         stateManager.setDsc(this);
65     }
66
67     /**
68      * Add a oid and state to the container. If this oid is allready in the
69      * container we just copy the values from the new state into the container's
70      * state.
71      * The state can later be looked up in by using the oid.
72      */

73     public int add(OID oid, State newState) {
74         addState(newState); //keep a ref to newState so it will not be gc'ed out of the cache
75
Integer JavaDoc integer = (Integer JavaDoc)oidMap.get(oid);
76         if (integer == null) {
77             // we do not have a ref to this state yet
78
if (size == capacity) {
79                 // make space for the new entry and copy it in
80
capacity = (capacity * 3) / 2 + 1;
81                 State[] ns = new State[capacity];
82                 System.arraycopy(states, 0, ns, 0, size);
83                 states = ns;
84                 PersistenceCapable[] npcs = new PersistenceCapable[capacity];
85                 System.arraycopy(pcs, 0, npcs, 0, size);
86                 pcs = npcs;
87                 OID[] noids = new OID[capacity];
88                 System.arraycopy(oids, 0, noids, 0, size);
89                 oids = noids;
90                 FetchGroup[][] nStateFG = new FetchGroup[capacity][];
91                 System.arraycopy(stateFG, 0, nStateFG, 0, size);
92                 stateFG = nStateFG;
93             }
94             states[size] = newState;
95             oids[size] = oid;
96             oidMap.put(oid, new Integer JavaDoc(size));
97             return size++;
98         } else {
99             // copy the values into the state we've allready got
100
int i = integer.intValue();
101             State realState = states[i];
102             if (realState == null) {
103                 states[i] = newState;
104             } else if (realState != newState) {
105                 if (newState != null) {
106                     realState.updateNonFilled(newState);
107                 }
108                 newState = realState;
109             }
110             return i;
111         }
112     }
113
114     /**
115      * Link the FetchGroup to this state.
116      */

117     public void add(OID oid, State newState, FetchGroup fg) {
118         int stateIndex = add(oid, newState);
119         if (fg == null) return;
120         if (newState != null) {
121             fg = fg.resolve(newState.getClassMetaData(modelMetaData));
122         }
123         for (FetchGroup superFG = fg; superFG != null;
124              superFG = superFG.superFetchGroup) {
125             addImpl(stateIndex, superFG);
126         }
127     }
128
129     public void addImpl(int stateIndex, FetchGroup fg) {
130         FetchGroup[] sfg = stateFG[stateIndex];
131         if (sfg == null) {
132             sfg = new FetchGroup[4];
133             stateFG[stateIndex] = sfg;
134         }
135         int length = sfg.length;
136         boolean add = true;
137         for (int i = 0; i < length; i++) {
138             FetchGroup fetchGroup = sfg[i];
139             if (fetchGroup == fg) {
140                 // we have this fetchGroup allready
141
return;
142             } else if (fetchGroup == null) {
143                 // we have space so add the fetchGroup
144
sfg[i] = fg;
145                 add = false;
146                 break;
147             }
148         }
149         if (add) {
150             // make space for the new fetchGroup and copy it in
151
int oldSize = sfg.length;
152             int newSize = oldSize * 2;
153             FetchGroup[] nfg = new FetchGroup[newSize];
154             System.arraycopy(sfg, 0, nfg, 0, oldSize);
155             sfg = nfg;
156             sfg[oldSize] = fg;
157             stateFG[stateIndex] = sfg;
158         }
159         if (sizeFG == capacityFG) {
160             // make space for the new entry and copy it in
161
capacityFG = (capacityFG * 3) / 2 + 1;
162             FetchGroup[] ng = new FetchGroup[capacityFG];
163             System.arraycopy(fetchGroups, 0, ng, 0, sizeFG);
164             fetchGroups = ng;
165             int[] nsi = new int[capacityFG];
166             System.arraycopy(stateIndexs, 0, nsi, 0, sizeFG);
167             stateIndexs = nsi;
168         }
169         fetchGroups[sizeFG] = fg;
170         stateIndexs[sizeFG] = stateIndex;
171         sizeFG++;
172     }
173
174     /**
175      * We keep a ref to these states so they will not be gc'ed out of the cache
176      */

177     private void addState(State newState) {
178         // make space for the new entry and copy in newState
179
if (sizeRefs == capacityRefs) {
180             capacityRefs = (capacityRefs * 3) / 2 + 1;
181             State[] ns = new State[capacityRefs];
182             System.arraycopy(stateRefs, 0, ns, 0, sizeRefs);
183             stateRefs = ns;
184         }
185         stateRefs[sizeRefs++] = newState;
186     }
187
188     /**
189      * todo
190      */

191     public void createPcClasses(ModelMetaData jmd) {
192         if (pcs[0] != null) return;
193         for (int i = 0; i < size; i++) {
194             PersistenceCapable pc = jdoImplHelper.newInstance(
195                     states[i].getClassMetaData(jmd).cls, stateManager);
196             if (!(pc instanceof VersantDetachable)) {
197                 throw BindingSupportImpl.getInstance().runtime("'" + pc.getClass().getName() + "' is not detachable please enhance " +
198                         "classes with the detach option set to true");
199             }
200             VersantDetachable detachable = (VersantDetachable)pc;
201             Object JavaDoc externalOID = pm.getExternalOID(oids[i]);
202             oidMap.put(externalOID, new Integer JavaDoc(i));
203             detachable.versantSetOID(externalOID);
204             detachable.versantSetVersion(states[i].getOptimisticLockingValue());
205             pcs[i] = detachable;
206         }
207         for (int i = 0; i < size; i++) {
208             PersistenceCapable pc = pcs[i];
209             ClassMetaData cmd = states[i].getClassMetaData(jmd);
210             FieldMetaData[] pkFields = cmd.top.pkFields;
211             if (pkFields != null) {
212                 for (int j = 0; j < pkFields.length; j++) {
213                     FieldMetaData fmd = cmd.pkFields[j];
214                     int managedFieldNo = fmd.managedFieldNo;
215                     if (!stateManager.isLoaded(pc, managedFieldNo)) {
216                         pc.jdoReplaceField(managedFieldNo);
217                     }
218
219                 }
220             }
221         }
222         for (int i = 0; i < size; i++) {
223             PersistenceCapable pc = pcs[i];
224             FetchGroup[] sfg = stateFG[i];
225             int sfgLength = sfg.length;
226             for (int cfg = 0; cfg < sfgLength; cfg++) {
227                 FetchGroup fg = sfg[cfg];
228                 if (fg == null) {
229                     break;
230                 }
231                 boolean defaultFG = fg == fg.classMetaData.fetchGroups[0];
232                 for (int j = 0; j < fg.fields.length; j++) {
233                     FetchGroupField field = fg.fields[j];
234                     FieldMetaData fmd = field.fmd;
235                     if (fmd.fake) continue;
236                     if (fmd.scoField) continue;
237                     if (defaultFG && !fmd.isJDODefaultFetchGroup()) continue;
238                     int managedFieldNo = fmd.managedFieldNo;
239                     if (stateManager.isLoaded(pc, managedFieldNo)) continue;
240                     pc.jdoReplaceField(managedFieldNo);
241                 }
242             }
243         }
244         for (int i = 0; i < size; i++) {
245             PersistenceCapable pc = pcs[i];
246             FetchGroup[] sfg = stateFG[i];
247             int sfgLength = sfg.length;
248             for (int cfg = 0; cfg < sfgLength; cfg++) {
249                 FetchGroup fg = sfg[cfg];
250                 if (fg == null) {
251                     break;
252                 }
253                 boolean defaultFG = fg == fg.classMetaData.fetchGroups[0];
254                 for (int j = 0; j < fg.fields.length; j++) {
255                     FetchGroupField field = fg.fields[j];
256                     FieldMetaData fmd = field.fmd;
257                     if (fmd.fake) continue;
258                     if (!fmd.scoField) continue;
259                     if (defaultFG && !fmd.isJDODefaultFetchGroup()) continue;
260                     int managedFieldNo = fmd.managedFieldNo;
261                     if (stateManager.isLoaded(pc, managedFieldNo)) continue;
262                     pc.jdoReplaceField(managedFieldNo);
263                 }
264             }
265         }
266         for (int i = 0; i < size; i++) {
267             pcs[i].jdoReplaceStateManager(detachedStateManager);
268         }
269     }
270
271     /**
272      * Are there more FetchGroups to be processed?
273      */

274     public boolean hasNextFetchGroup() {
275         posFG++;
276         return posFG < sizeFG;
277     }
278
279     /**
280      * Get the state for the current fetch group.
281      */

282     public State getNextFetchGroupState() {
283         return states[stateIndexs[posFG]];
284     }
285
286     /**
287      * Get the fetch group.
288      */

289     public FetchGroup getNextFetchGroup() {
290         return fetchGroups[posFG];
291     }
292
293     /**
294      * Get the OID for the current fetch group.
295      */

296     public OID getNextFetchGroupOID() {
297         return oids[stateIndexs[posFG]];
298     }
299
300     /**
301      * Do we have stuff for the oid?
302      */

303     public boolean contains(OID oid) {
304         if (oid == null) return false;
305         return oidMap.containsKey(oid);
306     }
307
308     /**
309      * Get the PC for the oid.
310      */

311     public PersistenceCapable getPC(OID oid) {
312         return pcs[((Integer JavaDoc)oidMap.get(oid)).intValue()];
313     }
314
315     public State getState(PersistenceCapable pc) {
316         Object JavaDoc oid = ((VersantDetachable)pc).versantGetOID();
317         Integer JavaDoc integer = (Integer JavaDoc)oidMap.get(oid);
318         if (integer == null) {
319             return null;
320         }
321         return states[integer.intValue()];
322     }
323
324     public Object JavaDoc getObjectField(VersantDetachable pc, int fieldNo) {
325         State state = getState(pc);
326         ClassMetaData cmd = state.getClassMetaData();
327         FieldMetaData fmd = cmd.stateFields[cmd.absToRel[fieldNo]];
328         int category = fmd.category;
329         Object JavaDoc o = state.getInternalObjectFieldAbs(fieldNo);
330
331         switch (category) {
332             case MDStatics.CATEGORY_COLLECTION:
333                 if (o != null) {
334                     VersantSCOCollectionFactory factory = scoFactoryRegistry.getJDOGenieSCOCollectionFactory(
335                             fmd);
336                     if (o instanceof VersantSCOCollection) {
337                         CollectionData collectionData = new CollectionData();
338                         ((VersantSCOCollection)o).fillCollectionData(
339                                 collectionData);
340                         collectionData.valueCount = getDetachCopy(
341                                 collectionData.values,
342                                 collectionData.valueCount);
343                         return factory.createSCOCollection(pc, pm,
344                                 detachedStateManager, fmd, collectionData);
345                     } else {
346                         CollectionData collectionData = new CollectionData();
347                         Object JavaDoc[] values = (Object JavaDoc[])o;
348                         int length = values.length;
349                         collectionData.values = new Object JavaDoc[length];
350                         System.arraycopy(values, 0, collectionData.values, 0,
351                                 length);
352                         collectionData.valueCount = collectionData.values.length;
353                         collectionData.valueCount = getDetachCopy(
354                                 collectionData.values,
355                                 collectionData.valueCount);
356                         return factory.createSCOCollection(pc, pm,
357                                 detachedStateManager, fmd, collectionData);
358                     }
359                 }
360                 break;
361             case MDStatics.CATEGORY_ARRAY:
362                 if (o != null) {
363                     if (!o.getClass().isArray()) return o;
364                     Class JavaDoc type = o.getClass().getComponentType();
365                     int length = Array.getLength(o);
366                     Object JavaDoc newArray = Array.newInstance(type, length);
367                     System.arraycopy(o, 0, newArray, 0, length);
368                     if (fmd.isElementTypePC()) {
369                         getDetachCopy((Object JavaDoc[])newArray, length);
370                     }
371                     return newArray;
372                 }
373                 break;
374             case MDStatics.CATEGORY_MAP:
375                 if (o != null) {
376                     VersantSCOMapFactory factory = scoFactoryRegistry.getJDOGenieSCOMapFactory(
377                             fmd);
378                     if (o instanceof VersantSCOMap) {
379                         MapData mapData = new MapData();
380                         ((VersantSCOMap)o).fillMapData(mapData);
381                         mapData.entryCount = getDetachCopy(mapData.keys,
382                                 mapData.entryCount);
383                         mapData.entryCount = getDetachCopy(mapData.values,
384                                 mapData.entryCount);
385                         return factory.createSCOHashMap(pc, pm,
386                                 detachedStateManager, fmd, mapData);
387                     } else {
388                         MapEntries entries = (MapEntries)o;
389                         MapData mapData = new MapData();
390                         mapData.entryCount = entries.keys.length;
391                         Object JavaDoc[] keys = new Object JavaDoc[mapData.entryCount];
392                         System.arraycopy(entries.keys, 0, keys, 0,
393                                 mapData.entryCount);
394                         Object JavaDoc[] values = new Object JavaDoc[mapData.entryCount];
395                         System.arraycopy(entries.values, 0, values, 0,
396                                 mapData.entryCount);
397                         mapData.keys = keys;
398                         mapData.values = values;
399                         mapData.entryCount = getDetachCopy(mapData.keys,
400                                 mapData.entryCount);
401                         mapData.entryCount = getDetachCopy(mapData.values,
402                                 mapData.entryCount);
403                         return factory.createSCOHashMap(pc, pm,
404                                 detachedStateManager, fmd, mapData);
405                     }
406                 }
407                 break;
408             case MDStatics.CATEGORY_EXTERNALIZED:
409                 if (o != null) {
410                     if (state.isResolvedForClient(fieldNo)){
411                         o = fmd.externalizer.toExternalForm(pm, o);
412                     }
413                     o = fmd.externalizer.fromExternalForm(pm, o);
414                 }
415                 return o;
416             case MDStatics.CATEGORY_REF:
417             case MDStatics.CATEGORY_POLYREF:
418                 if (o != null) {
419                     if (fmd.scoField) {
420                         VersantSCOFactory factory = scoFactoryRegistry.getJdoGenieSCOFactory(
421                                 fmd);
422                         return factory.createSCO(pc, pm, detachedStateManager,
423                                 fmd, o);
424                     } else {
425                         return getDetachCopy(o);
426                     }
427                 }
428                 break;
429         }
430         return o;
431     }
432
433     public PersistenceCapable getDetachCopy(OID oid) {
434         Integer JavaDoc integer = (Integer JavaDoc)oidMap.get(oid);
435         int index = integer == null ? -1 : integer.intValue();
436         if (index < 0) {
437             throw BindingSupportImpl.getInstance().exception(
438                     "Could not find detached copy of object with oid='" + oid + "'");
439         }
440         return pcs[index];
441     }
442
443     public PersistenceCapable getDetachCopy(PersistenceCapable pc) {
444         PCStateMan internalSM = pm.getInternalSM(pc);
445         return getDetachCopy(internalSM.oid);
446     }
447
448     public int getDetachCopy(Object JavaDoc[] objects, int count) {
449         count = Math.min(count, objects.length);
450         for (int i = 0; i < count; i++) {
451             Object JavaDoc o = objects[i];
452             if (o != null) {
453                 objects[i] = getDetachCopy(o);
454             } else {
455                 return i;
456             }
457         }
458         return count;
459     }
460
461     public Object JavaDoc getDetachCopy(Object JavaDoc o) {
462         if (o instanceof OID) {
463             return getDetachCopy((OID)o);
464         } else if (o instanceof PersistenceCapable) {
465             return getDetachCopy((PersistenceCapable)o);
466         }
467         return o;
468     }
469
470     public VersantDetachStateManager getStateManager() {
471         return stateManager;
472     }
473 }
474
Popular Tags