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.activation.Activator;
025: import com.db4o.ext.*;
026: import com.db4o.foundation.*;
027: import com.db4o.internal.marshall.*;
028: import com.db4o.internal.slots.*;
029: import com.db4o.reflect.*;
030:
031: /**
032: * @exclude
033: */
034: public class ObjectReference extends PersistentBase implements
035: ObjectInfo, Activator {
036:
037: private ClassMetadata _class;
038: private Object _object;
039: private VirtualAttributes _virtualAttributes;
040:
041: private ObjectReference _idPreceding;
042: private ObjectReference _idSubsequent;
043: private int _idSize;
044:
045: private ObjectReference _hcPreceding;
046: private ObjectReference _hcSubsequent;
047: private int _hcSize;
048: private int _hcHashcode; // redundant hashCode
049:
050: private int _lastTopLevelCallId;
051:
052: public ObjectReference() {
053: }
054:
055: public ObjectReference(int a_id) {
056: _id = a_id;
057: }
058:
059: public ObjectReference(ClassMetadata classMetadata, int id) {
060: _class = classMetadata;
061: _id = id;
062: }
063:
064: public void activate() {
065: synchronized (container().lock()) {
066: if (isActive()) {
067: return;
068: }
069: activate(container().transaction(), getObject(), 1, false);
070: }
071: }
072:
073: public void activate(Transaction ta, Object obj, int depth,
074: boolean isRefresh) {
075: activate1(ta, obj, depth, isRefresh);
076: ta.container().activatePending(ta);
077: }
078:
079: void activate1(Transaction ta, Object obj, int depth,
080: boolean isRefresh) {
081: if (obj instanceof Db4oTypeImpl) {
082: depth = ((Db4oTypeImpl) obj).adjustReadDepth(depth);
083: }
084: if (depth > 0) {
085: ObjectContainerBase container = ta.container();
086: if (isRefresh) {
087: logActivation(container, "refresh");
088: } else {
089: if (isActive()) {
090: if (obj != null) {
091: if (depth > 1) {
092: if (_class.config() != null) {
093: depth = _class.config()
094: .adjustActivationDepth(depth);
095: }
096: _class.activateFields(ta, obj, depth);
097: }
098: return;
099: }
100: }
101: logActivation(container, "activate");
102: }
103: read(ta, null, obj, depth,
104: Const4.ADD_MEMBERS_TO_ID_TREE_ONLY, false);
105: }
106: }
107:
108: private void logActivation(ObjectContainerBase container,
109: String event) {
110: logEvent(container, event, Const4.ACTIVATION);
111: }
112:
113: private void logEvent(ObjectContainerBase container, String event,
114: final int level) {
115: if (container.configImpl().messageLevel() > level) {
116: container.message("" + getID() + " " + event + " "
117: + _class.getName());
118: }
119: }
120:
121: public final void addExistingReferenceToIdTree(Transaction trans) {
122: if (!(_class instanceof PrimitiveFieldHandler)) {
123: trans.referenceSystem().addExistingReferenceToIdTree(this );
124: }
125: }
126:
127: /** return false if class not completely initialized, otherwise true **/
128: boolean continueSet(Transaction trans, int updateDepth) {
129: if (!bitIsTrue(Const4.CONTINUE)) {
130: return true;
131: }
132:
133: if (!_class.stateOKAndAncestors()) {
134: return false;
135: }
136:
137: if (DTrace.enabled) {
138: DTrace.CONTINUESET.log(getID());
139: }
140:
141: bitFalse(Const4.CONTINUE);
142:
143: MarshallingContext context = new MarshallingContext(trans,
144: this , updateDepth, true);
145: MarshallerFamily.current()._object.marshall(getObject(),
146: context);
147: Pointer4 pointer = context.allocateSlot();
148: Buffer buffer = context.ToWriteBuffer(pointer);
149:
150: ObjectContainerBase container = trans.container();
151: container.writeNew(trans, pointer, _class, buffer);
152:
153: Object obj = _object;
154: objectOnNew(trans, obj);
155:
156: if (!_class.isPrimitive()) {
157: _object = container._references.createYapRef(this , obj);
158: }
159:
160: setStateClean();
161: endProcessing();
162:
163: return true;
164: }
165:
166: private void objectOnNew(Transaction transaction, Object obj) {
167: ObjectContainerBase container = transaction.container();
168: container.callbacks().objectOnNew(transaction, obj);
169: _class.dispatchEvent(container, obj, EventDispatcher.NEW);
170: }
171:
172: public void deactivate(Transaction trans, int depth) {
173: if (depth > 0) {
174: Object obj = getObject();
175: if (obj != null) {
176: if (obj instanceof Db4oTypeImpl) {
177: ((Db4oTypeImpl) obj).preDeactivate();
178: }
179: ObjectContainerBase container = trans.container();
180: logActivation(container, "deactivate");
181: setStateDeactivated();
182: _class.deactivate(trans, obj, depth);
183: }
184: }
185: }
186:
187: public byte getIdentifier() {
188: return Const4.YAPOBJECT;
189: }
190:
191: public long getInternalID() {
192: return getID();
193: }
194:
195: public Object getObject() {
196: if (Platform4.hasWeakReferences()) {
197: return Platform4.getYapRefObject(_object);
198: }
199: return _object;
200: }
201:
202: public Object getObjectReference() {
203: return _object;
204: }
205:
206: public ObjectContainerBase container() {
207: if (_class == null) {
208: return null;
209: }
210: return _class.container();
211: }
212:
213: // this method will only work client-side or on
214: // single ObjectContainers, after the YapClass
215: // is set.
216: public Transaction transaction() {
217: ObjectContainerBase container = container();
218: if (container != null) {
219: return container.transaction();
220: }
221: return null;
222: }
223:
224: public Db4oUUID getUUID() {
225: VirtualAttributes va = virtualAttributes(transaction());
226: if (va != null && va.i_database != null) {
227: return new Db4oUUID(va.i_uuid, va.i_database.i_signature);
228: }
229: return null;
230: }
231:
232: public long getVersion() {
233: VirtualAttributes va = virtualAttributes(transaction());
234: if (va == null) {
235: return 0;
236: }
237: return va.i_version;
238: }
239:
240: public final ClassMetadata classMetadata() {
241: return _class;
242: }
243:
244: public void classMetadata(ClassMetadata classMetadata) {
245: _class = classMetadata;
246: }
247:
248: public int ownLength() {
249: throw Exceptions4.shouldNeverBeCalled();
250: }
251:
252: public VirtualAttributes produceVirtualAttributes() {
253: if (_virtualAttributes == null) {
254: _virtualAttributes = new VirtualAttributes();
255: }
256: return _virtualAttributes;
257: }
258:
259: final Object peekPersisted(Transaction trans, int depth) {
260: return read(trans, depth, Const4.TRANSIENT, false);
261: }
262:
263: final Object read(Transaction trans, int instantiationDepth,
264: int addToIDTree, boolean checkIDTree) {
265: return read(trans, null, null, instantiationDepth, addToIDTree,
266: checkIDTree);
267: }
268:
269: public final Object read(Transaction trans, StatefulBuffer buffer,
270: Object obj, int instantiationDepth, int addToIDTree,
271: boolean checkIDTree) {
272: UnmarshallingContext context = new UnmarshallingContext(trans,
273: buffer, this , addToIDTree, checkIDTree);
274: context.persistentObject(obj);
275: context.activationDepth(instantiationDepth);
276: return context.read();
277: }
278:
279: public final Object readPrefetch(Transaction trans,
280: StatefulBuffer buffer) {
281: return new UnmarshallingContext(trans, buffer, this ,
282: Const4.ADD_TO_ID_TREE, false).readPrefetch();
283: }
284:
285: public final void readThis(Transaction trans, Buffer buffer) {
286: if (Deploy.debug) {
287: System.out
288: .println("YapObject.readThis should never be called. All handling takes place in read");
289: }
290: }
291:
292: public void setObjectWeak(ObjectContainerBase container, Object obj) {
293: if (container._references._weak) {
294: if (_object != null) {
295: Platform4.killYapRef(_object);
296: }
297: _object = Platform4.createActiveObjectReference(
298: container._references._queue, this , obj);
299: } else {
300: _object = obj;
301: }
302: }
303:
304: public void setObject(Object obj) {
305: _object = obj;
306: }
307:
308: final void store(Transaction trans, ClassMetadata classMetadata,
309: Object obj) {
310: _object = obj;
311: _class = classMetadata;
312:
313: writeObjectBegin();
314:
315: int id = trans.container().newUserObject();
316: trans.slotFreePointerOnRollback(id);
317:
318: setID(id);
319:
320: // will be ended in continueset()
321: beginProcessing();
322:
323: bitTrue(Const4.CONTINUE);
324: }
325:
326: public void flagForDelete(int callId) {
327: _lastTopLevelCallId = -callId;
328: }
329:
330: public boolean isFlaggedForDelete() {
331: return _lastTopLevelCallId < 0;
332: }
333:
334: public void flagAsHandled(int callId) {
335: _lastTopLevelCallId = callId;
336: }
337:
338: public final boolean isFlaggedAsHandled(int callID) {
339: return _lastTopLevelCallId == callID;
340: }
341:
342: public final boolean isValid() {
343: return isValidId(getID()) && getObject() != null;
344: }
345:
346: public static final boolean isValidId(int id) {
347: return id > 0;
348: }
349:
350: public VirtualAttributes virtualAttributes() {
351: return _virtualAttributes;
352: }
353:
354: public VirtualAttributes virtualAttributes(Transaction trans) {
355: if (trans == null) {
356: return _virtualAttributes;
357: }
358: synchronized (trans.container().lock()) {
359: if (_virtualAttributes == null) {
360: if (_class.hasVirtualAttributes()) {
361: _virtualAttributes = new VirtualAttributes();
362: _class.readVirtualAttributes(trans, this );
363: }
364: } else {
365: if (!_virtualAttributes.suppliesUUID()) {
366: if (_class.hasVirtualAttributes()) {
367: _class.readVirtualAttributes(trans, this );
368: }
369: }
370: }
371: return _virtualAttributes;
372: }
373: }
374:
375: public void setVirtualAttributes(VirtualAttributes at) {
376: _virtualAttributes = at;
377: }
378:
379: public void writeThis(Transaction trans, Buffer buffer) {
380: if (Deploy.debug) {
381: System.out
382: .println("YapObject.writeThis should never be called.");
383: }
384: }
385:
386: public void writeUpdate(Transaction transaction, int updatedepth) {
387:
388: continueSet(transaction, updatedepth);
389: // make sure, a concurrent new, possibly triggered by objectOnNew
390: // is written to the file
391:
392: // preventing recursive
393: if (!beginProcessing()) {
394: return;
395: }
396:
397: Object obj = getObject();
398:
399: if (!objectCanUpdate(transaction, obj) || !isActive()
400: || obj == null) {
401: endProcessing();
402: return;
403: }
404:
405: if (Deploy.debug) {
406: if (!(getID() > 0)) {
407: throw new IllegalStateException("ID invalid");
408: }
409: if (_class == null) {
410: throw new IllegalStateException("ClassMetadata invalid");
411: }
412: }
413:
414: ObjectContainerBase container = transaction.container();
415:
416: logEvent(container, "update", Const4.STATE);
417:
418: setStateClean();
419:
420: transaction.writeUpdateDeleteMembers(getID(), _class,
421: container._handlers.arrayType(obj), 0);
422:
423: MarshallingContext context = new MarshallingContext(
424: transaction, this , updatedepth, false);
425: MarshallerFamily.current()._object.marshall(obj, context);
426: Pointer4 pointer = context.allocateSlot();
427: Buffer buffer = context.ToWriteBuffer(pointer);
428:
429: container.writeUpdate(transaction, pointer, classMetadata(),
430: buffer);
431: if (isActive()) {
432: setStateClean();
433: }
434: endProcessing();
435:
436: container.callbacks().objectOnUpdate(transaction, obj);
437: classMetadata().dispatchEvent(container, obj,
438: EventDispatcher.UPDATE);
439:
440: }
441:
442: private boolean objectCanUpdate(Transaction transaction, Object obj) {
443: ObjectContainerBase container = transaction.container();
444: return container.callbacks().objectCanUpdate(transaction, obj)
445: && _class.dispatchEvent(container, obj,
446: EventDispatcher.CAN_UPDATE);
447: }
448:
449: /***** HCTREE *****/
450:
451: public ObjectReference hc_add(ObjectReference newRef) {
452: if (newRef.getObject() == null) {
453: return this ;
454: }
455: newRef.hc_init();
456: return hc_add1(newRef);
457: }
458:
459: public void hc_init() {
460: _hcPreceding = null;
461: _hcSubsequent = null;
462: _hcSize = 1;
463: _hcHashcode = hc_getCode(getObject());
464: }
465:
466: private ObjectReference hc_add1(ObjectReference newRef) {
467: int cmp = hc_compare(newRef);
468: if (cmp < 0) {
469: if (_hcPreceding == null) {
470: _hcPreceding = newRef;
471: _hcSize++;
472: } else {
473: _hcPreceding = _hcPreceding.hc_add1(newRef);
474: if (_hcSubsequent == null) {
475: return hc_rotateRight();
476: }
477: return hc_balance();
478: }
479: } else {
480: if (_hcSubsequent == null) {
481: _hcSubsequent = newRef;
482: _hcSize++;
483: } else {
484: _hcSubsequent = _hcSubsequent.hc_add1(newRef);
485: if (_hcPreceding == null) {
486: return hc_rotateLeft();
487: }
488: return hc_balance();
489: }
490: }
491: return this ;
492: }
493:
494: private ObjectReference hc_balance() {
495: int cmp = _hcSubsequent._hcSize - _hcPreceding._hcSize;
496: if (cmp < -2) {
497: return hc_rotateRight();
498: } else if (cmp > 2) {
499: return hc_rotateLeft();
500: } else {
501: _hcSize = _hcPreceding._hcSize + _hcSubsequent._hcSize + 1;
502: return this ;
503: }
504: }
505:
506: private void hc_calculateSize() {
507: if (_hcPreceding == null) {
508: if (_hcSubsequent == null) {
509: _hcSize = 1;
510: } else {
511: _hcSize = _hcSubsequent._hcSize + 1;
512: }
513: } else {
514: if (_hcSubsequent == null) {
515: _hcSize = _hcPreceding._hcSize + 1;
516: } else {
517: _hcSize = _hcPreceding._hcSize + _hcSubsequent._hcSize
518: + 1;
519: }
520: }
521: }
522:
523: private int hc_compare(ObjectReference toRef) {
524: int cmp = toRef._hcHashcode - _hcHashcode;
525: if (cmp == 0) {
526: cmp = toRef._id - _id;
527: }
528: return cmp;
529: }
530:
531: public ObjectReference hc_find(Object obj) {
532: return hc_find(hc_getCode(obj), obj);
533: }
534:
535: private ObjectReference hc_find(int id, Object obj) {
536: int cmp = id - _hcHashcode;
537: if (cmp < 0) {
538: if (_hcPreceding != null) {
539: return _hcPreceding.hc_find(id, obj);
540: }
541: } else if (cmp > 0) {
542: if (_hcSubsequent != null) {
543: return _hcSubsequent.hc_find(id, obj);
544: }
545: } else {
546: if (obj == getObject()) {
547: return this ;
548: }
549: if (_hcPreceding != null) {
550: ObjectReference inPreceding = _hcPreceding.hc_find(id,
551: obj);
552: if (inPreceding != null) {
553: return inPreceding;
554: }
555: }
556: if (_hcSubsequent != null) {
557: return _hcSubsequent.hc_find(id, obj);
558: }
559: }
560: return null;
561: }
562:
563: private int hc_getCode(Object obj) {
564: int hcode = System.identityHashCode(obj);
565: if (hcode < 0) {
566: hcode = ~hcode;
567: }
568: return hcode;
569: }
570:
571: private ObjectReference hc_rotateLeft() {
572: ObjectReference tree = _hcSubsequent;
573: _hcSubsequent = tree._hcPreceding;
574: hc_calculateSize();
575: tree._hcPreceding = this ;
576: if (tree._hcSubsequent == null) {
577: tree._hcSize = 1 + _hcSize;
578: } else {
579: tree._hcSize = 1 + _hcSize + tree._hcSubsequent._hcSize;
580: }
581: return tree;
582: }
583:
584: private ObjectReference hc_rotateRight() {
585: ObjectReference tree = _hcPreceding;
586: _hcPreceding = tree._hcSubsequent;
587: hc_calculateSize();
588: tree._hcSubsequent = this ;
589: if (tree._hcPreceding == null) {
590: tree._hcSize = 1 + _hcSize;
591: } else {
592: tree._hcSize = 1 + _hcSize + tree._hcPreceding._hcSize;
593: }
594: return tree;
595: }
596:
597: private ObjectReference hc_rotateSmallestUp() {
598: if (_hcPreceding != null) {
599: _hcPreceding = _hcPreceding.hc_rotateSmallestUp();
600: return hc_rotateRight();
601: }
602: return this ;
603: }
604:
605: ObjectReference hc_remove(ObjectReference findRef) {
606: if (this == findRef) {
607: return hc_remove();
608: }
609: int cmp = hc_compare(findRef);
610: if (cmp <= 0) {
611: if (_hcPreceding != null) {
612: _hcPreceding = _hcPreceding.hc_remove(findRef);
613: }
614: }
615: if (cmp >= 0) {
616: if (_hcSubsequent != null) {
617: _hcSubsequent = _hcSubsequent.hc_remove(findRef);
618: }
619: }
620: hc_calculateSize();
621: return this ;
622: }
623:
624: public void hc_traverse(Visitor4 visitor) {
625: if (_hcPreceding != null) {
626: _hcPreceding.hc_traverse(visitor);
627: }
628: if (_hcSubsequent != null) {
629: _hcSubsequent.hc_traverse(visitor);
630: }
631:
632: // Traversing the leaves first allows to add ObjectReference
633: // nodes to different ReferenceSystem trees during commit
634:
635: visitor.visit(this );
636: }
637:
638: private ObjectReference hc_remove() {
639: if (_hcSubsequent != null && _hcPreceding != null) {
640: _hcSubsequent = _hcSubsequent.hc_rotateSmallestUp();
641: _hcSubsequent._hcPreceding = _hcPreceding;
642: _hcSubsequent.hc_calculateSize();
643: return _hcSubsequent;
644: }
645: if (_hcSubsequent != null) {
646: return _hcSubsequent;
647: }
648: return _hcPreceding;
649: }
650:
651: /***** IDTREE *****/
652:
653: ObjectReference id_add(ObjectReference newRef) {
654: newRef._idPreceding = null;
655: newRef._idSubsequent = null;
656: newRef._idSize = 1;
657: return id_add1(newRef);
658: }
659:
660: private ObjectReference id_add1(ObjectReference newRef) {
661: int cmp = newRef._id - _id;
662: if (cmp < 0) {
663: if (_idPreceding == null) {
664: _idPreceding = newRef;
665: _idSize++;
666: } else {
667: _idPreceding = _idPreceding.id_add1(newRef);
668: if (_idSubsequent == null) {
669: return id_rotateRight();
670: }
671: return id_balance();
672: }
673: } else if (cmp > 0) {
674: if (_idSubsequent == null) {
675: _idSubsequent = newRef;
676: _idSize++;
677: } else {
678: _idSubsequent = _idSubsequent.id_add1(newRef);
679: if (_idPreceding == null) {
680: return id_rotateLeft();
681: }
682: return id_balance();
683: }
684: }
685: return this ;
686: }
687:
688: private ObjectReference id_balance() {
689: int cmp = _idSubsequent._idSize - _idPreceding._idSize;
690: if (cmp < -2) {
691: return id_rotateRight();
692: } else if (cmp > 2) {
693: return id_rotateLeft();
694: } else {
695: _idSize = _idPreceding._idSize + _idSubsequent._idSize + 1;
696: return this ;
697: }
698: }
699:
700: private void id_calculateSize() {
701: if (_idPreceding == null) {
702: if (_idSubsequent == null) {
703: _idSize = 1;
704: } else {
705: _idSize = _idSubsequent._idSize + 1;
706: }
707: } else {
708: if (_idSubsequent == null) {
709: _idSize = _idPreceding._idSize + 1;
710: } else {
711: _idSize = _idPreceding._idSize + _idSubsequent._idSize
712: + 1;
713: }
714: }
715: }
716:
717: ObjectReference id_find(int id) {
718: int cmp = id - _id;
719: if (cmp > 0) {
720: if (_idSubsequent != null) {
721: return _idSubsequent.id_find(id);
722: }
723: } else if (cmp < 0) {
724: if (_idPreceding != null) {
725: return _idPreceding.id_find(id);
726: }
727: } else {
728: return this ;
729: }
730: return null;
731: }
732:
733: private ObjectReference id_rotateLeft() {
734: ObjectReference tree = _idSubsequent;
735: _idSubsequent = tree._idPreceding;
736: id_calculateSize();
737: tree._idPreceding = this ;
738: if (tree._idSubsequent == null) {
739: tree._idSize = _idSize + 1;
740: } else {
741: tree._idSize = _idSize + 1 + tree._idSubsequent._idSize;
742: }
743: return tree;
744: }
745:
746: private ObjectReference id_rotateRight() {
747: ObjectReference tree = _idPreceding;
748: _idPreceding = tree._idSubsequent;
749: id_calculateSize();
750: tree._idSubsequent = this ;
751: if (tree._idPreceding == null) {
752: tree._idSize = _idSize + 1;
753: } else {
754: tree._idSize = _idSize + 1 + tree._idPreceding._idSize;
755: }
756: return tree;
757: }
758:
759: private ObjectReference id_rotateSmallestUp() {
760: if (_idPreceding != null) {
761: _idPreceding = _idPreceding.id_rotateSmallestUp();
762: return id_rotateRight();
763: }
764: return this ;
765: }
766:
767: ObjectReference id_remove(int id) {
768: int cmp = id - _id;
769: if (cmp < 0) {
770: if (_idPreceding != null) {
771: _idPreceding = _idPreceding.id_remove(id);
772: }
773: } else if (cmp > 0) {
774: if (_idSubsequent != null) {
775: _idSubsequent = _idSubsequent.id_remove(id);
776: }
777: } else {
778: return id_remove();
779: }
780: id_calculateSize();
781: return this ;
782: }
783:
784: private ObjectReference id_remove() {
785: if (_idSubsequent != null && _idPreceding != null) {
786: _idSubsequent = _idSubsequent.id_rotateSmallestUp();
787: _idSubsequent._idPreceding = _idPreceding;
788: _idSubsequent.id_calculateSize();
789: return _idSubsequent;
790: }
791: if (_idSubsequent != null) {
792: return _idSubsequent;
793: }
794: return _idPreceding;
795: }
796:
797: public String toString() {
798: if (!Debug4.prettyToStrings) {
799: return super .toString();
800: }
801: try {
802: int id = getID();
803: String str = "ObjectReference\nID=" + id;
804: Object obj = getObject();
805: if (_class != null) {
806: ObjectContainerBase container = _class.container();
807: if (container != null && id > 0) {
808: obj = container.peekPersisted(
809: container.transaction(), id, 5, true)
810: .toString();
811: }
812: }
813: if (obj == null) {
814: str += "\nfor [null]";
815: } else {
816: String objToString = "";
817: try {
818: objToString = obj.toString();
819: } catch (Exception e) {
820: }
821: ReflectClass claxx = classMetadata().reflector()
822: .forObject(obj);
823: str += "\n" + claxx.getName() + "\n" + objToString;
824: }
825: return str;
826: } catch (Exception e) {
827: // e.printStackTrace();
828: }
829: return "Exception in YapObject analyzer";
830: }
831:
832: }
|