001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package com.db4o.internal;
022:
023: import com.db4o.*;
024: import com.db4o.ext.StoredClass;
025: import com.db4o.foundation.*;
026: import com.db4o.reflect.ReflectClass;
027:
028: /**
029: * @exclude
030: */
031: public final class ClassMetadataRepository extends PersistentBase {
032:
033: private Collection4 i_classes;
034: private Hashtable4 i_creating;
035:
036: private final Transaction _systemTransaction;
037:
038: private Hashtable4 i_yapClassByBytes;
039: private Hashtable4 i_yapClassByClass;
040: private Hashtable4 i_yapClassByID;
041:
042: private int i_yapClassCreationDepth;
043: private Queue4 i_initYapClassesOnUp;
044:
045: private final PendingClassInits _classInits;
046:
047: ClassMetadataRepository(Transaction systemTransaction) {
048: _systemTransaction = systemTransaction;
049: i_initYapClassesOnUp = new NonblockingQueue();
050: _classInits = new PendingClassInits(_systemTransaction);
051: }
052:
053: public void addYapClass(ClassMetadata yapClass) {
054: stream().setDirtyInSystemTransaction(this );
055: i_classes.add(yapClass);
056: if (yapClass.stateUnread()) {
057: i_yapClassByBytes.put(yapClass.i_nameBytes, yapClass);
058: } else {
059: i_yapClassByClass.put(yapClass.classReflector(), yapClass);
060: }
061: if (yapClass.getID() == 0) {
062: yapClass.write(_systemTransaction);
063: }
064: i_yapClassByID.put(yapClass.getID(), yapClass);
065: }
066:
067: private byte[] asBytes(String str) {
068: return stream().stringIO().write(str);
069: }
070:
071: public void attachQueryNode(final String fieldName,
072: final Visitor4 a_visitor) {
073: ClassMetadataIterator i = iterator();
074: while (i.moveNext()) {
075: final ClassMetadata classMetadata = i.currentClass();
076: if (!classMetadata.isInternal()) {
077: classMetadata.forEachFieldMetadata(new Visitor4() {
078: public void visit(Object obj) {
079: FieldMetadata yf = (FieldMetadata) obj;
080: if (yf.canAddToQuery(fieldName)) {
081: a_visitor.visit(new Object[] {
082: classMetadata, yf });
083: }
084: }
085: });
086: }
087: }
088: }
089:
090: public void iterateTopLevelClasses(Visitor4 visitor) {
091: ClassMetadataIterator i = iterator();
092: while (i.moveNext()) {
093: final ClassMetadata classMetadata = i.currentClass();
094: if (!classMetadata.isInternal()) {
095: if (classMetadata.getAncestor() == null) {
096: visitor.visit(classMetadata);
097: }
098: }
099: }
100: }
101:
102: void checkChanges() {
103: Iterator4 i = i_classes.iterator();
104: while (i.moveNext()) {
105: ((ClassMetadata) i.current()).checkChanges();
106: }
107: }
108:
109: final boolean createYapClass(ClassMetadata a_yapClass,
110: ReflectClass a_class) {
111: i_yapClassCreationDepth++;
112: ReflectClass super Class = a_class.getSuperclass();
113: ClassMetadata super YapClass = null;
114: if (super Class != null
115: && !super Class.equals(stream()._handlers.ICLASS_OBJECT)) {
116: super YapClass = produceClassMetadata(super Class);
117: }
118: boolean ret = stream().createClassMetadata(a_yapClass, a_class,
119: super YapClass);
120: i_yapClassCreationDepth--;
121: initYapClassesOnUp();
122: return ret;
123: }
124:
125: public static void defrag(BufferPair readers) {
126: if (Deploy.debug) {
127: readers.readBegin(Const4.YAPCLASSCOLLECTION);
128: }
129: int numClasses = readers.readInt();
130: for (int classIdx = 0; classIdx < numClasses; classIdx++) {
131: readers.copyID();
132: }
133: if (Deploy.debug) {
134: readers.readEnd();
135: }
136: }
137:
138: private void ensureAllClassesRead() {
139: boolean allClassesRead = false;
140: while (!allClassesRead) {
141: Collection4 unreadClasses = new Collection4();
142: int numClasses = i_classes.size();
143: Iterator4 classIter = i_classes.iterator();
144: while (classIter.moveNext()) {
145: ClassMetadata yapClass = (ClassMetadata) classIter
146: .current();
147: if (yapClass.stateUnread()) {
148: unreadClasses.add(yapClass);
149: }
150: }
151: Iterator4 unreadIter = unreadClasses.iterator();
152: while (unreadIter.moveNext()) {
153: ClassMetadata yapClass = (ClassMetadata) unreadIter
154: .current();
155: yapClass = readClassMetadata(yapClass, null);
156: if (yapClass.classReflector() == null) {
157: yapClass.forceRead();
158: }
159: }
160: allClassesRead = (i_classes.size() == numClasses);
161: }
162: applyReadAs();
163: }
164:
165: boolean fieldExists(String a_field) {
166: ClassMetadataIterator i = iterator();
167: while (i.moveNext()) {
168: if (i.currentClass().fieldMetadataForName(a_field) != null) {
169: return true;
170: }
171: }
172: return false;
173: }
174:
175: public Collection4 forInterface(ReflectClass claxx) {
176: Collection4 col = new Collection4();
177: ClassMetadataIterator i = iterator();
178: while (i.moveNext()) {
179: ClassMetadata yc = i.currentClass();
180: ReflectClass candidate = yc.classReflector();
181: if (!candidate.isInterface()) {
182: if (claxx.isAssignableFrom(candidate)) {
183: col.add(yc);
184: Iterator4 j = new Collection4(col).iterator();
185: while (j.moveNext()) {
186: ClassMetadata existing = (ClassMetadata) j
187: .current();
188: if (existing != yc) {
189: ClassMetadata higher = yc
190: .getHigherHierarchy(existing);
191: if (higher != null) {
192: if (higher == yc) {
193: col.remove(existing);
194: } else {
195: col.remove(yc);
196: }
197: }
198: }
199: }
200: }
201: }
202: }
203: return col;
204: }
205:
206: public byte getIdentifier() {
207: return Const4.YAPCLASSCOLLECTION;
208: }
209:
210: ClassMetadata getActiveYapClass(ReflectClass a_class) {
211: return (ClassMetadata) i_yapClassByClass.get(a_class);
212: }
213:
214: ClassMetadata classMetadataForReflectClass(ReflectClass a_class) {
215: ClassMetadata yapClass = (ClassMetadata) i_yapClassByClass
216: .get(a_class);
217: if (yapClass != null) {
218: return yapClass;
219: }
220: yapClass = (ClassMetadata) i_yapClassByBytes
221: .remove(getNameBytes(a_class.getName()));
222: return readClassMetadata(yapClass, a_class);
223: }
224:
225: ClassMetadata produceClassMetadata(ReflectClass claxx) {
226:
227: ClassMetadata classMetadata = classMetadataForReflectClass(claxx);
228:
229: if (classMetadata != null) {
230: return classMetadata;
231: }
232:
233: classMetadata = (ClassMetadata) i_creating.get(claxx);
234:
235: if (classMetadata != null) {
236: return classMetadata;
237: }
238:
239: classMetadata = new ClassMetadata(stream(), claxx);
240:
241: i_creating.put(claxx, classMetadata);
242:
243: if (!createYapClass(classMetadata, claxx)) {
244: i_creating.remove(claxx);
245: return null;
246: }
247:
248: // YapStream#createYapClass may add the YapClass already,
249: // so we have to check again
250:
251: boolean addMembers = false;
252:
253: if (i_yapClassByClass.get(claxx) == null) {
254: addYapClass(classMetadata);
255: addMembers = true;
256: }
257:
258: int id = classMetadata.getID();
259: if (id == 0) {
260: classMetadata.write(stream().systemTransaction());
261: id = classMetadata.getID();
262: }
263:
264: if (i_yapClassByID.get(id) == null) {
265: i_yapClassByID.put(id, classMetadata);
266: addMembers = true;
267: }
268:
269: if (addMembers || classMetadata.i_fields == null) {
270: _classInits.process(classMetadata);
271: }
272:
273: i_creating.remove(claxx);
274:
275: stream().setDirtyInSystemTransaction(this );
276:
277: return classMetadata;
278: }
279:
280: ClassMetadata getYapClass(int id) {
281: return readClassMetadata(
282: (ClassMetadata) i_yapClassByID.get(id), null);
283: }
284:
285: public int classMetadataIdForName(String name) {
286: ClassMetadata classMetadata = (ClassMetadata) i_yapClassByBytes
287: .get(getNameBytes(name));
288: if (classMetadata == null) {
289: classMetadata = findInitializedClassByName(name);
290: }
291: if (classMetadata != null) {
292: return classMetadata.getID();
293: }
294: return 0;
295: }
296:
297: public ClassMetadata getYapClass(String a_name) {
298: ClassMetadata classMetadata = (ClassMetadata) i_yapClassByBytes
299: .remove(getNameBytes(a_name));
300: if (classMetadata == null) {
301: classMetadata = findInitializedClassByName(a_name);
302: }
303: if (classMetadata != null) {
304: classMetadata = readClassMetadata(classMetadata, null);
305: }
306: return classMetadata;
307: }
308:
309: private ClassMetadata findInitializedClassByName(String name) {
310: ClassMetadataIterator i = iterator();
311: while (i.moveNext()) {
312: ClassMetadata classMetadata = (ClassMetadata) i.current();
313: if (name.equals(classMetadata.getName())) {
314: return classMetadata;
315: }
316: }
317: return null;
318: }
319:
320: public int getYapClassID(String name) {
321: ClassMetadata yc = (ClassMetadata) i_yapClassByBytes
322: .get(getNameBytes(name));
323: if (yc != null) {
324: return yc.getID();
325: }
326: return 0;
327: }
328:
329: byte[] getNameBytes(String name) {
330: return asBytes(resolveAliasRuntimeName(name));
331: }
332:
333: private String resolveAliasRuntimeName(String name) {
334: return stream().configImpl().resolveAliasRuntimeName(name);
335: }
336:
337: void initOnUp(Transaction systemTrans) {
338: i_yapClassCreationDepth++;
339: systemTrans.container().showInternalClasses(true);
340: try {
341: Iterator4 i = i_classes.iterator();
342: while (i.moveNext()) {
343: ((ClassMetadata) i.current()).initOnUp(systemTrans);
344: }
345: } finally {
346: systemTrans.container().showInternalClasses(false);
347: }
348: i_yapClassCreationDepth--;
349: initYapClassesOnUp();
350: }
351:
352: void initTables(int a_size) {
353: i_classes = new Collection4();
354: i_yapClassByBytes = new Hashtable4(a_size);
355: if (a_size < 16) {
356: a_size = 16;
357: }
358: i_yapClassByClass = new Hashtable4(a_size);
359: i_yapClassByID = new Hashtable4(a_size);
360: i_creating = new Hashtable4(1);
361: }
362:
363: private void initYapClassesOnUp() {
364: if (i_yapClassCreationDepth == 0) {
365: ClassMetadata yc = (ClassMetadata) i_initYapClassesOnUp
366: .next();
367: while (yc != null) {
368: yc.initOnUp(_systemTransaction);
369: yc = (ClassMetadata) i_initYapClassesOnUp.next();
370: }
371: }
372: }
373:
374: public ClassMetadataIterator iterator() {
375: return new ClassMetadataIterator(this , new ArrayIterator4(
376: i_classes.toArray()));
377: }
378:
379: private static class ClassIDIterator extends MappingIterator {
380:
381: public ClassIDIterator(Collection4 classes) {
382: super (classes.iterator());
383: }
384:
385: protected Object map(Object current) {
386: return new Integer(((ClassMetadata) current).getID());
387: }
388: }
389:
390: public Iterator4 ids() {
391: return new ClassIDIterator(i_classes);
392: }
393:
394: public int ownLength() {
395: return Const4.OBJECT_LENGTH + Const4.INT_LENGTH
396: + (i_classes.size() * Const4.ID_LENGTH);
397: }
398:
399: void purge() {
400: Iterator4 i = i_classes.iterator();
401: while (i.moveNext()) {
402: ((ClassMetadata) i.current()).purge();
403: }
404: }
405:
406: public final void readThis(Transaction a_trans, Buffer a_reader) {
407: int classCount = a_reader.readInt();
408:
409: initTables(classCount);
410:
411: ObjectContainerBase stream = stream();
412: int[] ids = new int[classCount];
413:
414: for (int i = 0; i < classCount; ++i) {
415: ids[i] = a_reader.readInt();
416: }
417: StatefulBuffer[] yapWriters = stream.readWritersByIDs(a_trans,
418: ids);
419:
420: for (int i = 0; i < classCount; ++i) {
421: ClassMetadata classMetadata = new ClassMetadata(stream,
422: null);
423: classMetadata.setID(ids[i]);
424: i_classes.add(classMetadata);
425: i_yapClassByID.put(ids[i], classMetadata);
426: byte[] name = classMetadata.readName1(a_trans,
427: yapWriters[i]);
428: if (name != null) {
429: i_yapClassByBytes.put(name, classMetadata);
430: }
431: }
432:
433: applyReadAs();
434:
435: }
436:
437: Hashtable4 classByBytes() {
438: return i_yapClassByBytes;
439: }
440:
441: private void applyReadAs() {
442: final Hashtable4 readAs = stream().configImpl().readAs();
443: Iterator4 i = readAs.iterator();
444: while (i.moveNext()) {
445: Entry4 entry = (Entry4) i.current();
446: String dbName = (String) entry.key();
447: String useName = (String) entry.value();
448: byte[] dbbytes = getNameBytes(dbName);
449: byte[] useBytes = getNameBytes(useName);
450: if (classByBytes().get(useBytes) == null) {
451: ClassMetadata yc = (ClassMetadata) classByBytes().get(
452: dbbytes);
453: if (yc != null) {
454: yc.i_nameBytes = useBytes;
455: yc.setConfig(configClass(dbName));
456: classByBytes().remove(dbbytes);
457: classByBytes().put(useBytes, yc);
458: }
459: }
460: }
461: }
462:
463: private Config4Class configClass(String name) {
464: return stream().configImpl().configClass(name);
465: }
466:
467: public ClassMetadata readClassMetadata(ClassMetadata classMetadata,
468: ReflectClass clazz) {
469: if (classMetadata == null) {
470: return null;
471: }
472: if (!classMetadata.stateUnread()) {
473: return classMetadata;
474: }
475: i_yapClassCreationDepth++;
476:
477: String name = classMetadata.resolveName(clazz);
478:
479: classMetadata.createConfigAndConstructor(i_yapClassByBytes,
480: clazz, name);
481: ReflectClass claxx = classMetadata.classReflector();
482: if (claxx != null) {
483: i_yapClassByClass.put(claxx, classMetadata);
484: classMetadata.readThis();
485: classMetadata.checkChanges();
486: i_initYapClassesOnUp.add(classMetadata);
487: }
488: i_yapClassCreationDepth--;
489: initYapClassesOnUp();
490: return classMetadata;
491: }
492:
493: public void refreshClasses() {
494: ClassMetadataRepository rereader = new ClassMetadataRepository(
495: _systemTransaction);
496: rereader._id = _id;
497: rereader.read(stream().systemTransaction());
498: Iterator4 i = rereader.i_classes.iterator();
499: while (i.moveNext()) {
500: ClassMetadata yc = (ClassMetadata) i.current();
501: if (i_yapClassByID.get(yc.getID()) == null) {
502: i_classes.add(yc);
503: i_yapClassByID.put(yc.getID(), yc);
504: if (yc.stateUnread()) {
505: i_yapClassByBytes.put(yc
506: .readName(_systemTransaction), yc);
507: } else {
508: i_yapClassByClass.put(yc.classReflector(), yc);
509: }
510: }
511: }
512: i = i_classes.iterator();
513: while (i.moveNext()) {
514: ClassMetadata yc = (ClassMetadata) i.current();
515: yc.refresh();
516: }
517: }
518:
519: void reReadYapClass(ClassMetadata yapClass) {
520: if (yapClass != null) {
521: reReadYapClass(yapClass.i_ancestor);
522: yapClass.readName(_systemTransaction);
523: yapClass.forceRead();
524: yapClass.setStateClean();
525: yapClass.bitFalse(Const4.CHECKED_CHANGES);
526: yapClass.bitFalse(Const4.READING);
527: yapClass.bitFalse(Const4.CONTINUE);
528: yapClass.bitFalse(Const4.DEAD);
529: yapClass.checkChanges();
530: }
531: }
532:
533: public StoredClass[] storedClasses() {
534: ensureAllClassesRead();
535: StoredClass[] sclasses = new StoredClass[i_classes.size()];
536: i_classes.toArray(sclasses);
537: return sclasses;
538: }
539:
540: public void writeAllClasses() {
541: StoredClass[] storedClasses = storedClasses();
542: for (int i = 0; i < storedClasses.length; i++) {
543: ClassMetadata yc = (ClassMetadata) storedClasses[i];
544: yc.setStateDirty();
545: }
546:
547: for (int i = 0; i < storedClasses.length; i++) {
548: ClassMetadata yc = (ClassMetadata) storedClasses[i];
549: yc.write(_systemTransaction);
550: }
551: }
552:
553: public void writeThis(Transaction trans, Buffer a_writer) {
554: a_writer.writeInt(i_classes.size());
555: Iterator4 i = i_classes.iterator();
556: while (i.moveNext()) {
557: a_writer.writeIDOf(trans, i.current());
558: }
559: }
560:
561: public String toString() {
562: if (!Debug4.prettyToStrings) {
563: return super .toString();
564: }
565: String str = "Active:\n";
566: Iterator4 i = i_classes.iterator();
567: while (i.moveNext()) {
568: ClassMetadata yc = (ClassMetadata) i.current();
569: str += yc.getID() + " " + yc + "\n";
570: }
571: return str;
572: }
573:
574: ObjectContainerBase stream() {
575: return _systemTransaction.container();
576: }
577:
578: public void setID(int a_id) {
579: if (stream().isClient()) {
580: super .setID(a_id);
581: return;
582: }
583:
584: if (_id == 0) {
585: systemData().classCollectionID(a_id);
586: }
587: super .setID(a_id);
588: }
589:
590: private SystemData systemData() {
591: return localSystemTransaction().file().systemData();
592: }
593:
594: private LocalTransaction localSystemTransaction() {
595: return ((LocalTransaction) _systemTransaction);
596: }
597:
598: }
|