/* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
This file is part of the db4o open source object database.
db4o is free software; you can redistribute it and/or modify it under
the terms of version 2 of the GNU General Public License as published
by the Free Software Foundation and as clarified by db4objects' GPL
interpretation policy, available at
http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
Suite 350, San Mateo, CA 94403, USA.
db4o is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
package com.db4o.internal;
import com.db4o.*;
import com.db4o.activation.Activator;
import com.db4o.ext.*;
import com.db4o.foundation.*;
import com.db4o.internal.marshall.*;
import com.db4o.internal.slots.*;
import com.db4o.reflect.*;
/**
* @exclude
*/
public class ObjectReference extends PersistentBase implements ObjectInfo, Activator {
private ClassMetadata _class;
private Object _object;
private VirtualAttributes _virtualAttributes;
private ObjectReference _idPreceding;
private ObjectReference _idSubsequent;
private int _idSize;
private ObjectReference _hcPreceding;
private ObjectReference _hcSubsequent;
private int _hcSize;
private int _hcHashcode; // redundant hashCode
private int _lastTopLevelCallId;
public ObjectReference(){
}
public ObjectReference(int a_id) {
_id = a_id;
}
public ObjectReference(ClassMetadata classMetadata, int id) {
_class = classMetadata;
_id = id;
}
public void activate() {
synchronized(container().lock()){
if (isActive()) {
return;
}
activate(container().transaction(), getObject(), 1, false);
}
}
public void activate(Transaction ta, Object obj, int depth, boolean isRefresh) {
activate1(ta, obj, depth, isRefresh);
ta.container().activatePending(ta);
}
void activate1(Transaction ta, Object obj, int depth, boolean isRefresh) {
if(obj instanceof Db4oTypeImpl){
depth = ((Db4oTypeImpl)obj).adjustReadDepth(depth);
}
if (depth > 0) {
ObjectContainerBase container = ta.container();
if(isRefresh){
logActivation(container, "refresh");
}else{
if (isActive()) {
if (obj != null) {
if (depth > 1) {
if (_class.config() != null) {
depth = _class.config().adjustActivationDepth(depth);
}
_class.activateFields(ta, obj, depth);
}
return;
}
}
logActivation(container, "activate");
}
read(ta, null, obj, depth, Const4.ADD_MEMBERS_TO_ID_TREE_ONLY, false);
}
}
private void logActivation(ObjectContainerBase container, String event) {
logEvent(container, event, Const4.ACTIVATION);
}
private void logEvent(ObjectContainerBase container, String event, final int level) {
if (container.configImpl().messageLevel() > level) {
container.message("" + getID() + " " + event + " " + _class.getName());
}
}
public final void addExistingReferenceToIdTree(Transaction trans) {
if (!(_class instanceof PrimitiveFieldHandler)) {
trans.referenceSystem().addExistingReferenceToIdTree(this);
}
}
/** return false if class not completely initialized, otherwise true **/
boolean continueSet(Transaction trans, int updateDepth) {
if (! bitIsTrue(Const4.CONTINUE)) {
return true;
}
if(! _class.stateOKAndAncestors()){
return false;
}
if(DTrace.enabled){
DTrace.CONTINUESET.log(getID());
}
bitFalse(Const4.CONTINUE);
MarshallingContext context = new MarshallingContext(trans, this, updateDepth, true);
MarshallerFamily.current()._object.marshall(getObject(), context);
Pointer4 pointer = context.allocateSlot();
Buffer buffer = context.ToWriteBuffer(pointer);
ObjectContainerBase container = trans.container();
container.writeNew(trans, pointer, _class, buffer);
Object obj = _object;
objectOnNew(trans, obj);
if(! _class.isPrimitive()){
_object = container._references.createYapRef(this, obj);
}
setStateClean();
endProcessing();
return true;
}
private void objectOnNew(Transaction transaction, Object obj) {
ObjectContainerBase container = transaction.container();
container.callbacks().objectOnNew(transaction, obj);
_class.dispatchEvent(container, obj, EventDispatcher.NEW);
}
public void deactivate(Transaction trans, int depth) {
if (depth > 0) {
Object obj = getObject();
if (obj != null) {
if(obj instanceof Db4oTypeImpl){
((Db4oTypeImpl)obj).preDeactivate();
}
ObjectContainerBase container = trans.container();
logActivation(container, "deactivate");
setStateDeactivated();
_class.deactivate(trans, obj, depth);
}
}
}
public byte getIdentifier() {
return Const4.YAPOBJECT;
}
public long getInternalID() {
return getID();
}
public Object getObject() {
if (Platform4.hasWeakReferences()) {
return Platform4.getYapRefObject(_object);
}
return _object;
}
public Object getObjectReference(){
return _object;
}
public ObjectContainerBase container(){
if(_class == null){
return null;
}
return _class.container();
}
// this method will only work client-side or on
// single ObjectContainers, after the YapClass
// is set.
public Transaction transaction(){
ObjectContainerBase container = container();
if(container != null){
return container.transaction();
}
return null;
}
public Db4oUUID getUUID(){
VirtualAttributes va = virtualAttributes(transaction());
if(va != null && va.i_database != null){
return new Db4oUUID(va.i_uuid, va.i_database.i_signature);
}
return null;
}
public long getVersion(){
VirtualAttributes va = virtualAttributes(transaction());
if(va == null) {
return 0;
}
return va.i_version;
}
public final ClassMetadata classMetadata() {
return _class;
}
public void classMetadata(ClassMetadata classMetadata) {
_class = classMetadata;
}
public int ownLength() {
throw Exceptions4.shouldNeverBeCalled();
}
public VirtualAttributes produceVirtualAttributes() {
if(_virtualAttributes == null){
_virtualAttributes = new VirtualAttributes();
}
return _virtualAttributes;
}
final Object peekPersisted(Transaction trans, int depth) {
return read(trans, depth, Const4.TRANSIENT, false);
}
final Object read (Transaction trans, int instantiationDepth,int addToIDTree,boolean checkIDTree) {
return read(trans, null, null, instantiationDepth, addToIDTree, checkIDTree);
}
public final Object read(
Transaction trans,
StatefulBuffer buffer,
Object obj,
int instantiationDepth,
int addToIDTree,
boolean checkIDTree) {
UnmarshallingContext context = new UnmarshallingContext(trans, buffer, this, addToIDTree, checkIDTree);
context.persistentObject(obj);
context.activationDepth(instantiationDepth);
return context.read();
}
public final Object readPrefetch(Transaction trans, StatefulBuffer buffer) {
return new UnmarshallingContext(trans, buffer, this, Const4.ADD_TO_ID_TREE, false).readPrefetch();
}
public final void readThis(Transaction trans, Buffer buffer) {
if (Deploy.debug) {
System.out.println(
"YapObject.readThis should never be called. All handling takes place in read");
}
}
public void setObjectWeak(ObjectContainerBase container, Object obj) {
if (container._references._weak) {
if(_object != null){
Platform4.killYapRef(_object);
}
_object = Platform4.createActiveObjectReference(container._references._queue, this, obj);
} else {
_object = obj;
}
}
public void setObject(Object obj) {
_object = obj;
}
final void store(Transaction trans, ClassMetadata classMetadata, Object obj){
_object = obj;
_class = classMetadata;
writeObjectBegin();
int id = trans.container().newUserObject();
trans.slotFreePointerOnRollback(id);
setID(id);
// will be ended in continueset()
beginProcessing();
bitTrue(Const4.CONTINUE);
}
public void flagForDelete(int callId){
_lastTopLevelCallId = - callId;
}
public boolean isFlaggedForDelete(){
return _lastTopLevelCallId < 0;
}
public void flagAsHandled(int callId){
_lastTopLevelCallId = callId;
}
public final boolean isFlaggedAsHandled(int callID){
return _lastTopLevelCallId == callID;
}
public final boolean isValid() {
return isValidId(getID()) && getObject() != null;
}
public static final boolean isValidId(int id){
return id > 0;
}
public VirtualAttributes virtualAttributes(){
return _virtualAttributes;
}
public VirtualAttributes virtualAttributes(Transaction trans){
if(trans == null){
return _virtualAttributes;
}
synchronized(trans.container().lock()){
if(_virtualAttributes == null){
if(_class.hasVirtualAttributes()){
_virtualAttributes = new VirtualAttributes();
_class.readVirtualAttributes(trans, this);
}
}else{
if(! _virtualAttributes.suppliesUUID()){
if(_class.hasVirtualAttributes()){
_class.readVirtualAttributes(trans, this);
}
}
}
return _virtualAttributes;
}
}
public void setVirtualAttributes(VirtualAttributes at){
_virtualAttributes = at;
}
public void writeThis(Transaction trans, Buffer buffer) {
if (Deploy.debug) {
System.out.println("YapObject.writeThis should never be called.");
}
}
public void writeUpdate(Transaction transaction, int updatedepth) {
continueSet(transaction, updatedepth);
// make sure, a concurrent new, possibly triggered by objectOnNew
// is written to the file
// preventing recursive
if ( !beginProcessing() ) {
return;
}
Object obj = getObject();
if( !objectCanUpdate(transaction, obj) || !isActive() || obj == null ){
endProcessing();
return;
}
if (Deploy.debug) {
if (!(getID() > 0)) {
throw new IllegalStateException("ID invalid");
}
if (_class == null) {
throw new IllegalStateException("ClassMetadata invalid");
}
}
ObjectContainerBase container = transaction.container();
logEvent(container, "update", Const4.STATE);
setStateClean();
transaction.writeUpdateDeleteMembers(getID(), _class, container._handlers.arrayType(obj), 0);
MarshallingContext context = new MarshallingContext(transaction, this, updatedepth, false);
MarshallerFamily.current()._object.marshall(obj, context);
Pointer4 pointer = context.allocateSlot();
Buffer buffer = context.ToWriteBuffer(pointer);
container.writeUpdate(transaction, pointer, classMetadata(), buffer);
if (isActive()) {
setStateClean();
}
endProcessing();
container.callbacks().objectOnUpdate(transaction, obj);
classMetadata().dispatchEvent(container, obj, EventDispatcher.UPDATE);
}
private boolean objectCanUpdate(Transaction transaction, Object obj) {
ObjectContainerBase container = transaction.container();
return container.callbacks().objectCanUpdate(transaction, obj)
&& _class.dispatchEvent(container, obj, EventDispatcher.CAN_UPDATE);
}
/***** HCTREE *****/
public ObjectReference hc_add(ObjectReference newRef) {
if (newRef.getObject() == null) {
return this;
}
newRef.hc_init();
return hc_add1(newRef);
}
public void hc_init(){
_hcPreceding = null;
_hcSubsequent = null;
_hcSize = 1;
_hcHashcode = hc_getCode(getObject());
}
private ObjectReference hc_add1(ObjectReference newRef) {
int cmp = hc_compare(newRef);
if (cmp < 0) {
if (_hcPreceding == null) {
_hcPreceding = newRef;
_hcSize++;
} else {
_hcPreceding = _hcPreceding.hc_add1(newRef);
if (_hcSubsequent == null) {
return hc_rotateRight();
}
return hc_balance();
}
} else {
if (_hcSubsequent == null) {
_hcSubsequent = newRef;
_hcSize++;
} else {
_hcSubsequent = _hcSubsequent.hc_add1(newRef);
if (_hcPreceding == null) {
return hc_rotateLeft();
}
return hc_balance();
}
}
return this;
}
private ObjectReference hc_balance() {
int cmp = _hcSubsequent._hcSize - _hcPreceding._hcSize;
if (cmp < -2) {
return hc_rotateRight();
} else if (cmp > 2) {
return hc_rotateLeft();
} else {
_hcSize = _hcPreceding._hcSize + _hcSubsequent._hcSize + 1;
return this;
}
}
private void hc_calculateSize() {
if (_hcPreceding == null) {
if (_hcSubsequent == null) {
_hcSize = 1;
} else {
_hcSize = _hcSubsequent._hcSize + 1;
}
} else {
if (_hcSubsequent == null) {
_hcSize = _hcPreceding._hcSize + 1;
} else {
_hcSize = _hcPreceding._hcSize + _hcSubsequent._hcSize + 1;
}
}
}
private int hc_compare(ObjectReference toRef) {
int cmp = toRef._hcHashcode - _hcHashcode;
if(cmp == 0){
cmp = toRef._id - _id;
}
return cmp;
}
public ObjectReference hc_find(Object obj) {
return hc_find(hc_getCode(obj), obj);
}
private ObjectReference hc_find(int id, Object obj) {
int cmp = id - _hcHashcode;
if (cmp < 0) {
if (_hcPreceding != null) {
return _hcPreceding.hc_find(id, obj);
}
} else if (cmp > 0) {
if (_hcSubsequent != null) {
return _hcSubsequent.hc_find(id, obj);
}
} else {
if (obj == getObject()) {
return this;
}
if (_hcPreceding != null) {
ObjectReference inPreceding = _hcPreceding.hc_find(id, obj);
if (inPreceding != null) {
return inPreceding;
}
}
if (_hcSubsequent != null) {
return _hcSubsequent.hc_find(id, obj);
}
}
return null;
}
private int hc_getCode(Object obj) {
int hcode = System.identityHashCode(obj);
if (hcode < 0) {
hcode = ~hcode;
}
return hcode;
}
private ObjectReference hc_rotateLeft() {
ObjectReference tree = _hcSubsequent;
_hcSubsequent = tree._hcPreceding;
hc_calculateSize();
tree._hcPreceding = this;
if(tree._hcSubsequent == null){
tree._hcSize = 1 + _hcSize;
}else{
tree._hcSize = 1 + _hcSize + tree._hcSubsequent._hcSize;
}
return tree;
}
private ObjectReference hc_rotateRight() {
ObjectReference tree = _hcPreceding;
_hcPreceding = tree._hcSubsequent;
hc_calculateSize();
tree._hcSubsequent = this;
if(tree._hcPreceding == null){
tree._hcSize = 1 + _hcSize;
}else{
tree._hcSize = 1 + _hcSize + tree._hcPreceding._hcSize;
}
return tree;
}
private ObjectReference hc_rotateSmallestUp() {
if (_hcPreceding != null) {
_hcPreceding = _hcPreceding.hc_rotateSmallestUp();
return hc_rotateRight();
}
return this;
}
ObjectReference hc_remove(ObjectReference findRef) {
if (this == findRef) {
return hc_remove();
}
int cmp = hc_compare(findRef);
if (cmp <= 0) {
if (_hcPreceding != null) {
_hcPreceding = _hcPreceding.hc_remove(findRef);
}
}
if (cmp >= 0) {
if (_hcSubsequent != null) {
_hcSubsequent = _hcSubsequent.hc_remove(findRef);
}
}
hc_calculateSize();
return this;
}
public void hc_traverse(Visitor4 visitor){
if(_hcPreceding != null){
_hcPreceding.hc_traverse(visitor);
}
if(_hcSubsequent != null){
_hcSubsequent.hc_traverse(visitor);
}
// Traversing the leaves first allows to add ObjectReference
// nodes to different ReferenceSystem trees during commit
visitor.visit(this);
}
private ObjectReference hc_remove() {
if (_hcSubsequent != null && _hcPreceding != null) {
_hcSubsequent = _hcSubsequent.hc_rotateSmallestUp();
_hcSubsequent._hcPreceding = _hcPreceding;
_hcSubsequent.hc_calculateSize();
return _hcSubsequent;
}
if (_hcSubsequent != null) {
return _hcSubsequent;
}
return _hcPreceding;
}
/***** IDTREE *****/
ObjectReference id_add(ObjectReference newRef) {
newRef._idPreceding = null;
newRef._idSubsequent = null;
newRef._idSize = 1;
return id_add1(newRef);
}
private ObjectReference id_add1(ObjectReference newRef) {
int cmp = newRef._id - _id;
if (cmp < 0) {
if (_idPreceding == null) {
_idPreceding = newRef;
_idSize++;
} else {
_idPreceding = _idPreceding.id_add1(newRef);
if (_idSubsequent == null) {
return id_rotateRight();
}
return id_balance();
}
} else if(cmp > 0) {
if (_idSubsequent == null) {
_idSubsequent = newRef;
_idSize++;
} else {
_idSubsequent = _idSubsequent.id_add1(newRef);
if (_idPreceding == null) {
return id_rotateLeft();
}
return id_balance();
}
}
return this;
}
private ObjectReference id_balance() {
int cmp = _idSubsequent._idSize - _idPreceding._idSize;
if (cmp < -2) {
return id_rotateRight();
} else if (cmp > 2) {
return id_rotateLeft();
} else {
_idSize = _idPreceding._idSize + _idSubsequent._idSize + 1;
return this;
}
}
private void id_calculateSize() {
if (_idPreceding == null) {
if (_idSubsequent == null) {
_idSize = 1;
} else {
_idSize = _idSubsequent._idSize + 1;
}
} else {
if (_idSubsequent == null) {
_idSize = _idPreceding._idSize + 1;
} else {
_idSize = _idPreceding._idSize + _idSubsequent._idSize + 1;
}
}
}
ObjectReference id_find(int id) {
int cmp = id - _id;
if (cmp > 0) {
if (_idSubsequent != null) {
return _idSubsequent.id_find(id);
}
} else if (cmp < 0) {
if (_idPreceding != null) {
return _idPreceding.id_find(id);
}
} else {
return this;
}
return null;
}
private ObjectReference id_rotateLeft() {
ObjectReference tree = _idSubsequent;
_idSubsequent = tree._idPreceding;
id_calculateSize();
tree._idPreceding = this;
if(tree._idSubsequent == null){
tree._idSize = _idSize + 1;
}else{
tree._idSize = _idSize + 1 + tree._idSubsequent._idSize;
}
return tree;
}
private ObjectReference id_rotateRight() {
ObjectReference tree = _idPreceding;
_idPreceding = tree._idSubsequent;
id_calculateSize();
tree._idSubsequent = this;
if(tree._idPreceding == null){
tree._idSize = _idSize + 1;
}else{
tree._idSize = _idSize + 1 + tree._idPreceding._idSize;
}
return tree;
}
private ObjectReference id_rotateSmallestUp() {
if (_idPreceding != null) {
_idPreceding = _idPreceding.id_rotateSmallestUp();
return id_rotateRight();
}
return this;
}
ObjectReference id_remove(int id) {
int cmp = id - _id;
if (cmp < 0) {
if (_idPreceding != null) {
_idPreceding = _idPreceding.id_remove(id);
}
} else if (cmp > 0) {
if (_idSubsequent != null) {
_idSubsequent = _idSubsequent.id_remove(id);
}
} else {
return id_remove();
}
id_calculateSize();
return this;
}
private ObjectReference id_remove() {
if (_idSubsequent != null && _idPreceding != null) {
_idSubsequent = _idSubsequent.id_rotateSmallestUp();
_idSubsequent._idPreceding = _idPreceding;
_idSubsequent.id_calculateSize();
return _idSubsequent;
}
if (_idSubsequent != null) {
return _idSubsequent;
}
return _idPreceding;
}
public String toString(){
if(! Debug4.prettyToStrings){
return super.toString();
}
try{
int id = getID();
String str = "ObjectReference\nID=" + id;
Object obj = getObject();
if(_class != null){
ObjectContainerBase container = _class.container();
if(container != null && id > 0){
obj = container.peekPersisted(container.transaction(), id, 5, true).toString();
}
}
if(obj == null){
str += "\nfor [null]";
}else{
String objToString ="";
try{
objToString = obj.toString();
}catch(Exception e){
}
ReflectClass claxx = classMetadata().reflector().forObject(obj);
str += "\n" + claxx.getName() + "\n" + objToString;
}
return str;
}catch(Exception e){
// e.printStackTrace();
}
return "Exception in YapObject analyzer";
}
}
|