/* 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.foundation.*; import com.db4o.internal.handlers.*; import com.db4o.internal.handlers.array.*; import com.db4o.internal.marshall.*; import com.db4o.marshall.*; import com.db4o.reflect.*; import com.db4o.typehandlers.*; /** * @exclude */ public class Handlers4 { public static final int INT_ID = 1; public static final int LONG_ID = 2; public static final int FLOAT_ID = 3; public static final int BOOLEAN_ID = 4; public static final int DOUBLE_ID = 5; public static final int BYTE_ID = 6; public static final int CHAR_ID = 7; public static final int SHORT_ID = 8; public static final int STRING_ID = 9; public static final int DATE_ID = 10; public static final int UNTYPED_ID = 11; public static final int ANY_ARRAY_ID = 12; public static final int ANY_ARRAY_N_ID = 13; public static boolean isQueryLeaf(TypeHandler4 handler){ TypeHandler4 baseTypeHandler = baseTypeHandler(handler); if (!(baseTypeHandler instanceof QueryableTypeHandler)) { return false; } if (baseTypeHandler instanceof ArrayHandler) { return false; } return baseTypeHandler instanceof ValueTypeHandler; } public static boolean handlesArray(TypeHandler4 handler){ return handler instanceof ArrayHandler; } public static boolean handlesMultidimensionalArray(TypeHandler4 handler){ return handler instanceof MultidimensionalArrayHandler; } public static boolean handlesClass(TypeHandler4 handler){ return baseTypeHandler(handler) instanceof CascadingTypeHandler; } public static ReflectClass primitiveClassReflector(TypeHandler4 handler, Reflector reflector){ TypeHandler4 baseTypeHandler = baseTypeHandler(handler); if(baseTypeHandler instanceof PrimitiveHandler){ return ((PrimitiveHandler)baseTypeHandler).primitiveClassReflector(); } return null; } public static TypeHandler4 baseTypeHandler(TypeHandler4 handler){ if(handler instanceof ArrayHandler){ return ((ArrayHandler)handler).delegateTypeHandler(); } if(handler instanceof PrimitiveTypeMetadata){ return ((PrimitiveTypeMetadata)handler).typeHandler(); } return handler; } public static ReflectClass baseType(ReflectClass clazz){ if(clazz == null){ return null; } if(clazz.isArray()){ return baseType(clazz.getComponentType()); } return clazz; } public static boolean isClassAware(TypeHandler4 typeHandler){ return typeHandler instanceof BuiltinTypeHandler || typeHandler instanceof StandardReferenceTypeHandler; } public static int calculateLinkLength(TypeHandler4 handler){ if (handler == null) { throw new ArgumentNullException(); } if (handler instanceof LinkLengthAware) { return ((LinkLengthAware) handler).linkLength(); } if (handler instanceof ReferenceTypeHandler) { return Const4.ID_LENGTH; } if(handler instanceof VariableLengthTypeHandler){ return Const4.INDIRECTION_LENGTH; } // TODO: For custom handlers there will have to be a way // to calculate the length in the slot. // Options: // (1) Remember when the first object is marshalled. // (2) Add a #defaultValue() method to TypeHandler4, // marshall the default value and check. // (3) Add a way to test the custom handler when it // is installed and remember the length there. throw new NotImplementedException("Unexpected typehandler: " + handler); } public static boolean holdsValueType(TypeHandler4 handler) { return isValueType(baseTypeHandler(handler)); } public static boolean isValueType(TypeHandler4 handler) { return !(handler instanceof ReferenceTypeHandler); } public static boolean isCascading(TypeHandler4 handler) { return handler instanceof CascadingTypeHandler; } public static boolean isUntyped(TypeHandler4 handler) { return handler instanceof OpenTypeHandler; } public static boolean isVariableLength(TypeHandler4 handler) { return handler instanceof VariableLengthTypeHandler; } public static FieldAwareTypeHandler fieldAwareTypeHandler(TypeHandler4 typeHandler) { if(typeHandler instanceof FieldAwareTypeHandler){ return (FieldAwareTypeHandler) typeHandler; } return NullFieldAwareTypeHandler.INSTANCE; } public static void collectIDs(final QueryingReadContext context, TypeHandler4 typeHandler) { if(typeHandler instanceof CascadingTypeHandler){ ((CascadingTypeHandler)typeHandler).collectIDs(context); } } public static boolean useDedicatedSlot(Context context, TypeHandler4 handler) { if (isValueType(handler)) { return false; } if (isUntyped(handler)) { return false; } return true; } public static TypeHandler4 arrayElementHandler(TypeHandler4 handler, QueryingReadContext queryingReadContext) { if(! (handler instanceof CascadingTypeHandler)){ return null; } CascadingTypeHandler cascadingHandler = (CascadingTypeHandler) HandlerRegistry.correctHandlerVersion(queryingReadContext, handler); return HandlerRegistry.correctHandlerVersion(queryingReadContext, cascadingHandler.readCandidateHandler(queryingReadContext)); } public static Object nullRepresentationInUntypedArrays(TypeHandler4 handler){ if (handler instanceof PrimitiveHandler){ return ((PrimitiveHandler) handler).nullRepresentationInUntypedArrays(); } return null; } public static boolean handleAsObject(TypeHandler4 typeHandler){ if(isValueType(typeHandler)){ return false; } if(isUntyped(typeHandler)){ return false; } return true; } public static void cascadeActivation(ActivationContext context, TypeHandler4 handler) { if(! (handler instanceof CascadingTypeHandler)){ return; } ((CascadingTypeHandler)handler).cascadeActivation(context); } public static boolean handlesPrimitiveArray(TypeHandler4 typeHandler) { return typeHandler instanceof ArrayHandler; // && isPrimitive(((ArrayHandler)typeHandler).delegateTypeHandler()); } public static boolean hasClassIndex(TypeHandler4 typeHandler) { if(typeHandler instanceof StandardReferenceTypeHandler){ return ((StandardReferenceTypeHandler)typeHandler).classMetadata().hasClassIndex(); } return false; } public static boolean canLoadFieldByIndex(TypeHandler4 handler) { if (handler instanceof QueryableTypeHandler) { return !((QueryableTypeHandler)handler).descendsIntoMembers(); } return true; } public static Object wrapWithTransactionContext(Transaction transaction, Object value, TypeHandler4 handler) { if(isValueType(handler)) { return value; } return transaction.wrap(value); } public static void collectIdsInternal(CollectIdContext context, final TypeHandler4 handler, int linkLength, boolean doWithSlotIndirection) { if(! (isCascading(handler))){ ReadBuffer buffer = context.buffer(); buffer.seek(buffer.offset() + linkLength); return; } if (handler instanceof StandardReferenceTypeHandler) { context.addId(); return; } LocalObjectContainer container = (LocalObjectContainer) context.container(); final SlotFormat slotFormat = context.slotFormat(); if(handleAsObject(handler)){ // TODO: Code is similar to QCandidate.readArrayCandidates. Try to refactor to one place. int collectionID = context.readInt(); ByteArrayBuffer collectionBuffer = container.readBufferById(context.transaction(), collectionID); ObjectHeader objectHeader = new ObjectHeader(container, collectionBuffer); QueryingReadContext subContext = new QueryingReadContext(context.transaction(), context.handlerVersion(), collectionBuffer, collectionID, context.collector()); objectHeader.classMetadata().collectIDs(subContext); return; } final QueryingReadContext queryingReadContext = new QueryingReadContext(context.transaction(), context.handlerVersion(), context.buffer(), 0, context.collector()); final Closure4 collectIDsFromQueryingContext = new Closure4() { public Object run() { ((CascadingTypeHandler) handler).collectIDs(queryingReadContext); return null; } }; if (doWithSlotIndirection) { slotFormat.doWithSlotIndirection(queryingReadContext, handler, collectIDsFromQueryingContext); } else { collectIDsFromQueryingContext.run(); } } public static boolean isIndirectedIndexed(TypeHandler4 handler) { return isValueType(handler) && (handler instanceof VariableLengthTypeHandler) && (handler instanceof IndexableTypeHandler); } public static PreparedComparison prepareComparisonFor(TypeHandler4 handler, Context context, Object obj) { if (!(handler instanceof Comparable4)) { return null; } return ((Comparable4)handler).prepareComparison(context, obj); } public static ReflectClass primitiveClassReflector(ClassMetadata classMetadata, Reflector reflector) { if(classMetadata instanceof PrimitiveTypeMetadata){ return primitiveClassReflector(((PrimitiveTypeMetadata)classMetadata).typeHandler(), reflector); } return null; } public static void activate(UnmarshallingContext context, TypeHandler4 handler) { if (handler instanceof ReferenceTypeHandler) { ((ReferenceTypeHandler)handler).activate(context); } } public static void write(TypeHandler4 handler, WriteContext context, Object obj) { handler.write(context, obj); } public static Object readValueType(ReadContext context, TypeHandler4 handler) { return ((ValueTypeHandler)handler).read(context); } public static boolean isStandaloneTypeHandler(TypeHandler4 customTypeHandler) { return isValueType(customTypeHandler) || customTypeHandler instanceof OpenTypeHandler; } public static ClassMetadata erasedFieldType(final ObjectContainerBase container, final ReflectClass fieldType) { return fieldType.isInterface() ? container.classMetadataForID(UNTYPED_ID) : container.produceClassMetadata(baseType(fieldType)); } }