com.db4o.YapObject Maven / Gradle / Ivy
The newest version!
/* Copyright (C) 2004 - 2005 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;
import com.db4o.ext.*;
import com.db4o.foundation.*;
import com.db4o.reflect.*;
/**
*/
public class YapObject extends YapMeta implements ObjectInfo{
private YapClass i_yapClass;
Object i_object;
VirtualAttributes i_virtualAttributes;
protected YapObject id_preceding;
private YapObject id_subsequent;
private int id_size;
private YapObject hc_preceding;
private YapObject hc_subsequent;
private int hc_size;
private int hc_code; // redundant hashCode
public YapObject(){
}
YapObject(int a_id) {
i_id = a_id;
}
YapObject(YapClass a_yapClass, int a_id) {
i_yapClass = a_yapClass;
i_id = a_id;
}
void activate(Transaction ta, Object a_object, int a_depth, boolean a_refresh) {
activate1(ta, a_object, a_depth, a_refresh);
ta.i_stream.activate3CheckStill(ta);
}
void activate1(Transaction ta, Object a_object, int a_depth, boolean a_refresh) {
if(a_object instanceof Db4oTypeImpl){
a_depth = ((Db4oTypeImpl)a_object).adjustReadDepth(a_depth);
}
if (a_depth > 0) {
YapStream stream = ta.i_stream;
if(a_refresh){
if (stream.i_config.i_messageLevel > YapConst.ACTIVATION) {
stream.message("" + getID() + " refresh " + i_yapClass.getName());
}
}else{
if (isActive()) {
if (a_object != null) {
if (a_depth > 1) {
if (i_yapClass.i_config != null) {
a_depth = i_yapClass.i_config.adjustActivationDepth(a_depth);
}
i_yapClass.activateFields(ta, a_object, a_depth);
}
return;
}
}
if (stream.i_config.i_messageLevel > YapConst.ACTIVATION) {
stream.message("" + getID() + " activate " + i_yapClass.getName());
}
}
read(ta, null, a_object, a_depth, YapConst.ADD_MEMBERS_TO_ID_TREE_ONLY, false);
}
}
final void addToIDTree(YapStream a_stream) {
if (!(i_yapClass instanceof YapClassPrimitive)) {
a_stream.idTreeAdd(this);
}
}
/** return false if class not completely initialized, otherwise true **/
boolean continueSet(Transaction a_trans, int a_updateDepth) {
if (bitIsTrue(YapConst.CONTINUE)) {
if(! i_yapClass.stateOKAndAncestors()){
return false;
}
if(DTrace.enabled){
DTrace.CONTINUESET.log(getID());
}
YapStream stream = a_trans.i_stream;
bitFalse(YapConst.CONTINUE);
Object obj = getObject();
int id = getID();
int length = ownLength();
int address = -1;
if(! stream.isClient()){
address = ((YapFile)stream).getSlot(length);
}
a_trans.setPointer(id, address, length);
YapWriter writer = new YapWriter(a_trans, length);
writer.useSlot(id, address, length);
if (Deploy.debug) {
writer.writeBegin(getIdentifier(), length);
}
writer.setUpdateDepth(a_updateDepth);
writer.writeInt(i_yapClass.getID());
i_yapClass.marshallNew(this, writer, obj);
if (Deploy.debug) {
writer.writeEnd();
writer.debugCheckBytes();
}
stream.writeNew(i_yapClass, writer);
i_yapClass.dispatchEvent(stream, obj, EventDispatcher.NEW);
// TODO: Weak reference creation not necessary for
// primitive objects, since reference to YapObject
// should get lost immediately
i_object = stream.i_references.createYapRef(this, obj);
setStateClean();
endProcessing();
}
return true;
}
void deactivate(Transaction a_trans, int a_depth) {
if (a_depth > 0) {
Object obj = getObject();
if (obj != null) {
if(obj instanceof Db4oTypeImpl){
((Db4oTypeImpl)obj).preDeactivate();
}
YapStream stream = a_trans.i_stream;
if (stream.i_config.i_messageLevel > YapConst.ACTIVATION) {
stream.message("" + getID() + " deactivate " + i_yapClass.getName());
}
setStateDeactivated();
i_yapClass.deactivate(a_trans, obj, a_depth);
}
}
}
byte getIdentifier() {
return YapConst.YAPOBJECT;
}
public Object getObject() {
if (Platform4.hasWeakReferences()) {
return Platform4.getYapRefObject(i_object);
}
return i_object;
}
// this method will only work client-side or on
// single ObjectContainers, after the YapClass
// is set.
public Transaction getTrans(){
if(i_yapClass != null){
YapStream stream = i_yapClass.getStream();
if(stream != null){
return stream.getTransaction();
}
}
return null;
}
public Db4oUUID getUUID(){
VirtualAttributes va = virtualAttributes(getTrans());
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(getTrans());
if(va == null) {
return 0;
}
return va.i_version;
}
public YapClass getYapClass() {
return i_yapClass;
}
int ownLength() {
return i_yapClass.objectLength();
}
final Object read(
Transaction ta,
YapWriter a_reader,
Object a_object,
int a_instantiationDepth,
int addToIDTree,
boolean checkIDTree) {
// a_instantiationDepth is a way of overriding instantiation
// in a positive manner
if (beginProcessing()) {
YapStream stream = ta.i_stream;
if (a_reader == null) {
a_reader = stream.readWriterByID(ta, getID());
}
if (a_reader != null) {
i_yapClass = readYapClass(a_reader);
if (i_yapClass == null) {
return null;
}
if(checkIDTree){
// the typical side effect: static fields and enums
YapObject classCreationSideEffect = stream.getYapObject(getID());
if(classCreationSideEffect != null){
Object obj = classCreationSideEffect.getObject();
if(obj != null){
return obj;
}
stream.yapObjectGCd(classCreationSideEffect);
}
}
a_reader.setInstantiationDepth(a_instantiationDepth);
a_reader.setUpdateDepth(addToIDTree);
if(addToIDTree == YapConst.TRANSIENT){
a_object = i_yapClass.instantiateTransient(this, a_object, a_reader);
}else{
a_object = i_yapClass.instantiate(this, a_object, a_reader, addToIDTree == YapConst.ADD_TO_ID_TREE);
}
}
endProcessing();
}
return a_object;
}
final Object readPrefetch(YapStream a_stream, Transaction ta, YapWriter a_reader) {
Object readObject = null;
if (beginProcessing()) {
i_yapClass = readYapClass(a_reader);
if (i_yapClass == null) {
return null;
}
// We use an instantiationdepth of 1 only, if there is no special
// configuration for the class. This is a quick fix due to a problem
// instantiating Hashtables. There may be a better workaround that
// works with configured objects only to make them fast also.
//
// An instantiation depth of 1 makes use of possibly prefetched strings
// that are carried around in a_bytes.
//
// TODO: optimize
a_reader.setInstantiationDepth(i_yapClass.configOrAncestorConfig() == null ? 1 : 0);
readObject = i_yapClass.instantiate(this, getObject(), a_reader, true);
endProcessing();
}
return readObject;
}
final void readThis(Transaction a_trans, YapReader a_bytes) {
if (Deploy.debug) {
System.out.println(
"YapObject.readThis should never be called. All handling takes place in read");
}
}
private final YapClass readYapClass(YapWriter a_reader) {
if (Deploy.debug) {
a_reader.readBegin(getID(), getIdentifier());
}
return a_reader.getStream().getYapClass(a_reader.readInt());
}
void setID(YapStream a_stream, int a_id) {
i_id = a_id;
}
void setObjectWeak(YapStream a_stream, Object a_object) {
if (a_stream.i_references._weak) {
if(i_object != null){
Platform4.killYapRef(i_object);
}
i_object = Platform4.createYapRef(a_stream.i_references._queue, this, a_object);
} else {
i_object = a_object;
}
}
public void setObject(Object a_object) {
i_object = a_object;
}
void setStateOnRead(YapWriter reader) {
// Do nothing
}
/** return true for complex objects to instruct YapStream to add to lookup trees
* and to perform delayed storage through call to continueset further up the stack.
*/
boolean store(Transaction a_trans, YapClass a_yapClass, Object a_object, int a_updateDepth){
i_object = a_object;
writeObjectBegin();
YapStream stream = a_trans.i_stream;
i_yapClass = a_yapClass;
if (i_yapClass.getID() == YapHandlers.ANY_ID) {
// Storing naked objects does not make sense
// TODO: why?
throw new ObjectNotStorableException(i_yapClass.classReflector());
}
setID(stream, stream.newUserObject());
// will be ended in continueset()
beginProcessing();
bitTrue(YapConst.CONTINUE);
// We may still consider to have Arrays as full objects.
// It would need special handling, to remove them from
// hc_tree in the transaction, so currently it's ugly.
// Removing SecondClass objects from the reference tree
// causes problems in C/S cascaded delete.
if (/*!(a_object instanceof SecondClass) && */
!(i_yapClass instanceof YapClassPrimitive) /*|| clazz.isArray()*/
) {
return true;
} else {
// Primitive Objects will not be stored
// in the identity map.
continueSet(a_trans, a_updateDepth);
}
return false;
}
public VirtualAttributes virtualAttributes(Transaction a_trans){
if(a_trans == null){
return i_virtualAttributes;
}
if(i_virtualAttributes == null){
if(i_yapClass.hasVirtualAttributes()){
i_virtualAttributes = new VirtualAttributes();
i_yapClass.readVirtualAttributes(a_trans, this);
}
}else{
if(i_virtualAttributes.i_database == null || i_virtualAttributes.i_uuid == 0){
if(i_yapClass.hasVirtualAttributes()){
i_yapClass.readVirtualAttributes(a_trans, this);
}
}
}
return i_virtualAttributes;
}
public void setVirtualAttributes(VirtualAttributes at){
i_virtualAttributes = at;
}
void writeThis(YapWriter a_writer) {
if (Deploy.debug) {
System.out.println("YapObject.writeThis should never be called.");
}
}
void writeUpdate(Transaction a_trans, int a_updatedepth) {
continueSet(a_trans, a_updatedepth);
// make sure, a concurrent new, possibly triggered by objectOnNew
// is written to the file
// preventing recursive
if (beginProcessing()) {
Object obj = getObject();
if(i_yapClass.dispatchEvent(a_trans.i_stream, obj, EventDispatcher.CAN_UPDATE)){
if ((!isActive()) || obj == null) {
endProcessing();
return;
}
if (Deploy.debug) {
if (!(getID() > 0)) {
System.out.println(
"Object passed to set() with valid YapObject. YapObject had no ID.");
throw new RuntimeException();
}
if (i_yapClass == null) {
System.out.println(
"Object passed to set() with valid YapObject. YapObject has no valid yapClass.");
throw new RuntimeException();
}
}
if (a_trans.i_stream.i_config.i_messageLevel > YapConst.STATE) {
a_trans.i_stream.message("" + getID() + " update " + i_yapClass.getName());
}
setStateClean();
a_trans.writeUpdateDeleteMembers(getID(), i_yapClass, a_trans.i_stream.i_handlers.arrayType(obj), 0);
i_yapClass.marshallUpdate(a_trans, getID(), a_updatedepth, this, obj);
} else{
endProcessing();
}
}
}
/***** HCTREE *****/
public YapObject hc_add(YapObject a_add) {
Object obj = a_add.getObject();
if (obj != null) {
a_add.hc_init(obj);
return hc_add1(a_add);
} else {
return this;
}
}
public void hc_init(Object obj){
hc_preceding = null;
hc_subsequent = null;
hc_size = 1;
hc_code = hc_getCode(obj);
}
private YapObject hc_add1(YapObject a_new) {
int cmp = hc_compare(a_new);
if (cmp < 0) {
if (hc_preceding == null) {
hc_preceding = a_new;
hc_size++;
} else {
hc_preceding = hc_preceding.hc_add1(a_new);
if (hc_subsequent == null) {
return hc_rotateRight();
} else {
return hc_balance();
}
}
} else {
if (hc_subsequent == null) {
hc_subsequent = a_new;
hc_size++;
} else {
hc_subsequent = hc_subsequent.hc_add1(a_new);
if (hc_preceding == null) {
return hc_rotateLeft();
} else {
return hc_balance();
}
}
}
return this;
}
private YapObject hc_balance() {
int cmp = hc_subsequent.hc_size - hc_preceding.hc_size;
if (cmp < -2) {
return hc_rotateRight();
} else if (cmp > 2) {
return hc_rotateLeft();
} else {
hc_size = hc_preceding.hc_size + hc_subsequent.hc_size + 1;
return this;
}
}
private void hc_calculateSize() {
if (hc_preceding == null) {
if (hc_subsequent == null) {
hc_size = 1;
} else {
hc_size = hc_subsequent.hc_size + 1;
}
} else {
if (hc_subsequent == null) {
hc_size = hc_preceding.hc_size + 1;
} else {
hc_size = hc_preceding.hc_size + hc_subsequent.hc_size + 1;
}
}
}
private int hc_compare(YapObject a_to) {
int cmp = a_to.hc_code - hc_code;
if(cmp == 0){
cmp = a_to.i_id - i_id;
}
return cmp;
}
public YapObject hc_find(Object obj) {
return hc_find(hc_getCode(obj), obj);
}
private YapObject hc_find(int a_id, Object obj) {
int cmp = a_id - hc_code;
if (cmp < 0) {
if (hc_preceding != null) {
return hc_preceding.hc_find(a_id, obj);
}
} else if (cmp > 0) {
if (hc_subsequent != null) {
return hc_subsequent.hc_find(a_id, obj);
}
} else {
if (obj == getObject()) {
return this;
}
if (hc_preceding != null) {
YapObject inPreceding = hc_preceding.hc_find(a_id, obj);
if (inPreceding != null) {
return inPreceding;
}
}
if (hc_subsequent != null) {
return hc_subsequent.hc_find(a_id, obj);
}
}
return null;
}
private int hc_getCode(Object obj) {
int hcode = System.identityHashCode(obj);
if (hcode < 0) {
hcode = ~hcode;
}
return hcode;
}
private YapObject hc_rotateLeft() {
YapObject tree = hc_subsequent;
hc_subsequent = tree.hc_preceding;
hc_calculateSize();
tree.hc_preceding = this;
if(tree.hc_subsequent == null){
tree.hc_size = 1 + hc_size;
}else{
tree.hc_size = 1 + hc_size + tree.hc_subsequent.hc_size;
}
return tree;
}
private YapObject hc_rotateRight() {
YapObject tree = hc_preceding;
hc_preceding = tree.hc_subsequent;
hc_calculateSize();
tree.hc_subsequent = this;
if(tree.hc_preceding == null){
tree.hc_size = 1 + hc_size;
}else{
tree.hc_size = 1 + hc_size + tree.hc_preceding.hc_size;
}
return tree;
}
private YapObject hc_rotateSmallestUp() {
if (hc_preceding != null) {
hc_preceding = hc_preceding.hc_rotateSmallestUp();
return hc_rotateRight();
}
return this;
}
YapObject hc_remove(YapObject a_find) {
if (this == a_find) {
return hc_remove();
}
int cmp = hc_compare(a_find);
if (cmp <= 0) {
if (hc_preceding != null) {
hc_preceding = hc_preceding.hc_remove(a_find);
}
}
if (cmp >= 0) {
if (hc_subsequent != null) {
hc_subsequent = hc_subsequent.hc_remove(a_find);
}
}
hc_calculateSize();
return this;
}
public void hc_traverse(Visitor4 visitor){
if(hc_preceding != null){
hc_preceding.hc_traverse(visitor);
}
visitor.visit(this);
if(hc_subsequent != null){
hc_subsequent.hc_traverse(visitor);
}
}
private YapObject hc_remove() {
if (hc_subsequent != null && hc_preceding != null) {
hc_subsequent = hc_subsequent.hc_rotateSmallestUp();
hc_subsequent.hc_preceding = hc_preceding;
hc_subsequent.hc_calculateSize();
return hc_subsequent;
}
if (hc_subsequent != null) {
return hc_subsequent;
}
return hc_preceding;
}
/***** IDTREE *****/
YapObject id_add(YapObject a_add) {
a_add.id_preceding = null;
a_add.id_subsequent = null;
a_add.id_size = 1;
return id_add1(a_add);
}
private YapObject id_add1(YapObject a_new) {
int cmp = a_new.i_id - i_id;
if (cmp < 0) {
if (id_preceding == null) {
id_preceding = a_new;
id_size++;
} else {
id_preceding = id_preceding.id_add1(a_new);
if (id_subsequent == null) {
return id_rotateRight();
} else {
return id_balance();
}
}
} else {
if (id_subsequent == null) {
id_subsequent = a_new;
id_size++;
} else {
id_subsequent = id_subsequent.id_add1(a_new);
if (id_preceding == null) {
return id_rotateLeft();
} else {
return id_balance();
}
}
}
return this;
}
private YapObject id_balance() {
int cmp = id_subsequent.id_size - id_preceding.id_size;
if (cmp < -2) {
return id_rotateRight();
} else if (cmp > 2) {
return id_rotateLeft();
} else {
id_size = id_preceding.id_size + id_subsequent.id_size + 1;
return this;
}
}
private void id_calculateSize() {
if (id_preceding == null) {
if (id_subsequent == null) {
id_size = 1;
} else {
id_size = id_subsequent.id_size + 1;
}
} else {
if (id_subsequent == null) {
id_size = id_preceding.id_size + 1;
} else {
id_size = id_preceding.id_size + id_subsequent.id_size + 1;
}
}
}
YapObject id_find(int a_id) {
int cmp = a_id - i_id;
if (cmp > 0) {
if (id_subsequent != null) {
return id_subsequent.id_find(a_id);
}
} else if (cmp < 0) {
if (id_preceding != null) {
return id_preceding.id_find(a_id);
}
} else {
return this;
}
return null;
}
private YapObject id_rotateLeft() {
YapObject tree = id_subsequent;
id_subsequent = tree.id_preceding;
id_calculateSize();
tree.id_preceding = this;
if(tree.id_subsequent == null){
tree.id_size = id_size + 1;
}else{
tree.id_size = id_size + 1 + tree.id_subsequent.id_size;
}
return tree;
}
private YapObject id_rotateRight() {
YapObject tree = id_preceding;
id_preceding = tree.id_subsequent;
id_calculateSize();
tree.id_subsequent = this;
if(tree.id_preceding == null){
tree.id_size = id_size + 1;
}else{
tree.id_size = id_size + 1 + tree.id_preceding.id_size;
}
return tree;
}
private YapObject id_rotateSmallestUp() {
if (id_preceding != null) {
id_preceding = id_preceding.id_rotateSmallestUp();
return id_rotateRight();
}
return this;
}
YapObject id_remove(int a_id) {
int cmp = a_id - i_id;
if (cmp < 0) {
if (id_preceding != null) {
id_preceding = id_preceding.id_remove(a_id);
}
} else if (cmp > 0) {
if (id_subsequent != null) {
id_subsequent = id_subsequent.id_remove(a_id);
}
} else {
return id_remove();
}
id_calculateSize();
return this;
}
private YapObject id_remove() {
if (id_subsequent != null && id_preceding != null) {
id_subsequent = id_subsequent.id_rotateSmallestUp();
id_subsequent.id_preceding = id_preceding;
id_subsequent.id_calculateSize();
return id_subsequent;
}
if (id_subsequent != null) {
return id_subsequent;
}
return id_preceding;
}
public String toString(){
if(! Debug4.prettyToStrings){
return super.toString();
}
try{
int id = getID();
String str = "YapObject\nID=" + id;
if(i_yapClass != null){
YapStream stream = i_yapClass.getStream();
if(stream != null && id > 0){
YapWriter writer = stream.readWriterByID(stream.getTransaction(), id);
if(writer != null){
str += "\nAddress=" + writer.getAddress();
}
YapClass yc = readYapClass(writer);
if(yc != i_yapClass){
str += "\nYapClass corruption";
}else{
str += yc.toString(writer, this, 0, 5);
}
}
}
Object obj = getObject();
if(obj == null){
str += "\nfor [null]";
}else{
String objToString ="";
try{
objToString = obj.toString();
}catch(Exception e){
}
ReflectClass claxx = getYapClass().reflector().forObject(obj);
str += "\n" + claxx.getName() + "\n" + objToString;
}
return str;
}catch(Exception e){
// e.printStackTrace();
}
return "Exception in YapObject analyzer";
}
// Unused, keep for possible future use
// public void remarshall(Transaction trans){
// YapStream stream = trans.i_stream;
// YapWriter writer = stream.readWriterByID(trans, getID());
// writer._offset = 0;
// if (Deploy.debug) {
// writer.writeBegin(YapConst.YAPOBJECT, writer.getLength());
// }
// writer.writeInt(i_yapClass.getID());
// i_yapClass.marshall(this, getObject(), writer, false);
// if (Deploy.debug) {
// writer.writeEnd();
// writer.debugCheckBytes();
// }
//
// if(Deploy.debug){
// if(stream instanceof YapFile){
// YapFile yf = (YapFile)stream;
// yf.writeXBytes(writer.getAddress(), writer.getLength());
// }
// }
// writer.writeEncrypt();
// }
}