/* This file is part of the db4o object database http://www.db4o.com Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com db4o is free software; you can redistribute it and/or modify it under the terms of version 3 of the GNU General Public License as published by the Free Software Foundation. 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, see http://www.gnu.org/licenses/. */ package com.db4o.internal; import com.db4o.ext.*; import com.db4o.internal.delete.*; import com.db4o.internal.handlers.*; import com.db4o.internal.handlers.versions.*; import com.db4o.internal.marshall.*; import com.db4o.marshall.*; import com.db4o.reflect.*; import com.db4o.typehandlers.*; public class OpenTypeHandler implements ReferenceTypeHandler, ValueTypeHandler, BuiltinTypeHandler, CascadingTypeHandler, LinkLengthAware { private static final int HASHCODE = 1003303143; private ObjectContainerBase _container; public OpenTypeHandler(ObjectContainerBase container){ _container = container; } ObjectContainerBase container() { return _container; } public ReflectClass classReflector() { return container().handlers().ICLASS_OBJECT; } public void cascadeActivation(ActivationContext context){ Object targetObject = context.targetObject(); if(isPlainObject(targetObject)){ return; } TypeHandler4 typeHandler = typeHandlerForObject(targetObject); Handlers4.cascadeActivation(context, typeHandler); } public void delete(DeleteContext context) throws Db4oIOException { int payLoadOffset = context.readInt(); if(context.isLegacyHandlerVersion()){ context.defragmentRecommended(); return; } if (payLoadOffset <= 0) { return; } int linkOffset = context.offset(); context.seek(payLoadOffset); int classMetadataID = context.readInt(); TypeHandler4 typeHandler = container().classMetadataForID(classMetadataID).typeHandler(); if(typeHandler != null){ if(! isPlainObject(typeHandler)){ context.delete(typeHandler); } } context.seek(linkOffset); } public int getID() { return Handlers4.UNTYPED_ID; } public boolean hasField(ObjectContainerBase a_stream, String a_path) { return a_stream.classCollection().fieldExists(a_path); } public TypeHandler4 readCandidateHandler(QueryingReadContext context) { int payLoadOffSet = context.readInt(); if(payLoadOffSet == 0){ return null; } context.seek(payLoadOffSet); int classMetadataID = context.readInt(); ClassMetadata classMetadata = context.container().classMetadataForID(classMetadataID); if(classMetadata == null){ return null; } return classMetadata.readCandidateHandler(context); } public ObjectID readObjectID(InternalReadContext context){ int payloadOffset = context.readInt(); if(payloadOffset == 0){ return ObjectID.IS_NULL; } int savedOffset = context.offset(); TypeHandler4 typeHandler = readTypeHandler(context, payloadOffset); if(typeHandler == null){ context.seek(savedOffset); return ObjectID.IS_NULL; } seekSecondaryOffset(context, typeHandler); if(typeHandler instanceof ReadsObjectIds){ ObjectID readObjectID = ((ReadsObjectIds)typeHandler).readObjectID(context); context.seek(savedOffset); return readObjectID; } context.seek(savedOffset); return ObjectID.NOT_POSSIBLE; } public void defragment(DefragmentContext context) { int payLoadOffSet = context.readInt(); if(payLoadOffSet == 0){ return; } int savedOffSet = context.offset(); context.seek(payLoadOffSet); try{ int classMetadataId = context.copyIDReturnOriginalID(); TypeHandler4 typeHandler = correctTypeHandlerVersionFor(context, classMetadataId); if(typeHandler == null){ return; } seekSecondaryOffset(context, typeHandler); if(isPlainObject(typeHandler)){ context.defragment(new PlainObjectHandler()); }else{ context.defragment(typeHandler); } }finally{ context.seek(savedOffSet); } } protected TypeHandler4 correctTypeHandlerVersionFor(DefragmentContext context, int classMetadataId) { TypeHandler4 typeHandler = context.typeHandlerForId(classMetadataId); if (null == typeHandler) { return null; } ClassMetadata classMetadata = container(context).classMetadataForID(classMetadataId); return HandlerRegistry.correctHandlerVersion(context, typeHandler, classMetadata); } protected ObjectContainerBase container(DefragmentContext context) { return context.transaction().container(); } protected TypeHandler4 readTypeHandler(InternalReadContext context, int payloadOffset) { context.seek(payloadOffset); TypeHandler4 typeHandler = container().typeHandlerForClassMetadataID(context.readInt()); return HandlerRegistry.correctHandlerVersion(context, typeHandler); } /** * @param buffer * @param typeHandler */ protected void seekSecondaryOffset(ReadBuffer buffer, TypeHandler4 typeHandler) { // do nothing, no longer needed in current implementation. } public Object read(ReadContext readContext) { InternalReadContext context = (InternalReadContext) readContext; int payloadOffset = context.readInt(); if(payloadOffset == 0){ context.notifyNullReferenceSkipped(); return null; } int savedOffSet = context.offset(); try{ TypeHandler4 typeHandler = readTypeHandler(context, payloadOffset); if(typeHandler == null){ return null; } seekSecondaryOffset(context, typeHandler); if(isPlainObject(typeHandler)){ return context.readAtCurrentSeekPosition(new PlainObjectHandler()); } return context.readAtCurrentSeekPosition(typeHandler); } finally{ context.seek(savedOffSet); } } public void activate(ReferenceActivationContext context) { // throw new IllegalStateException(); } public void collectIDs(final QueryingReadContext readContext) { InternalReadContext context = (InternalReadContext) readContext; int payloadOffset = context.readInt(); if(payloadOffset == 0){ return; } int savedOffSet = context.offset(); try { TypeHandler4 typeHandler = readTypeHandler(context, payloadOffset); if(typeHandler == null){ return; } seekSecondaryOffset(context, typeHandler); if (isPlainObject(typeHandler)) { readContext.collector().addId(readContext.readInt()); return; } CollectIdContext collectIdContext = new CollectIdContext(readContext.transaction(), readContext.collector(), null, readContext.buffer()) { @Override public int handlerVersion() { return readContext.handlerVersion(); } @Override public SlotFormat slotFormat() { return new SlotFormatCurrent() { @Override public boolean isIndirectedWithinSlot(TypeHandler4 handler) { return false; } }; } }; Handlers4.collectIdsInternal(collectIdContext, context.container().handlers().correctHandlerVersion(typeHandler, context.handlerVersion()), 0, false); } finally { context.seek(savedOffSet); } } public TypeHandler4 readTypeHandlerRestoreOffset(InternalReadContext context){ int savedOffset = context.offset(); int payloadOffset = context.readInt(); TypeHandler4 typeHandler = payloadOffset == 0 ? null : readTypeHandler(context, payloadOffset); context.seek(savedOffset); return typeHandler; } public void write(WriteContext context, Object obj) { if(obj == null) { context.writeInt(0); return; } MarshallingContext marshallingContext = (MarshallingContext) context; ClassMetadata classMetadata = classMetadataFor(obj); if (classMetadata == null) { context.writeInt(0); return; } MarshallingContextState state = marshallingContext.currentState(); marshallingContext.createChildBuffer(false); context.writeInt(classMetadata.getID()); writeObject(context, classMetadata.typeHandler(), obj); marshallingContext.restoreState(state); } private ClassMetadata classMetadataFor(Object obj) { return container().classMetadataForObject(obj); } private void writeObject(WriteContext context, TypeHandler4 typeHandler, Object obj) { if(isPlainObject(obj)){ context.writeObject(new PlainObjectHandler(), obj); return; } if(Handlers4.useDedicatedSlot(context, typeHandler)){ context.writeObject(obj); }else { typeHandler.write(context, obj); } } private boolean isPlainObject(Object obj) { if(obj == null){ return false; } return obj.getClass() == Const4.CLASS_OBJECT; } public static boolean isPlainObject(TypeHandler4 typeHandler) { return typeHandler.getClass() == OpenTypeHandler.class || typeHandler.getClass() == OpenTypeHandler0.class || typeHandler.getClass() == OpenTypeHandler2.class || typeHandler.getClass() == OpenTypeHandler7.class; } public TypeHandler4 typeHandlerForObject(Object obj) { return classMetadataFor(obj).typeHandler(); } public boolean equals(Object obj) { return obj instanceof OpenTypeHandler && !(obj instanceof InterfaceTypeHandler); } public int hashCode() { return HASHCODE; } public void registerReflector(Reflector reflector) { // nothing to do } public int linkLength() { return Const4.ID_LENGTH; } }