private NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo IntrospectArray(object
                                                                                     array, bool introspect, System.Collections.Generic.IDictionary <object, NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeObjectInfo
                                                                                                                                                     > alreadyReadObjects, NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType valueType, NeoDatis.Odb.Core.Layers.Layer1.Introspector.IIntrospectionCallback
                                                                                     callback)
        {
            int length = NeoDatis.Tool.Wrappers.OdbReflection.GetArrayLength(array);

            System.Type elementType = array.GetType().GetElementType();
            NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType type = NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType
                                                                .GetFromClass(elementType);
            if (type.IsAtomicNative())
            {
                return(IntropectAtomicNativeArray(array, type));
            }
            if (!introspect)
            {
                return(new NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo((object[])array));
            }
            object[] arrayCopy = new object[length];
            for (int i = 0; i < length; i++)
            {
                object o = NeoDatis.Tool.Wrappers.OdbReflection.GetArrayElement(array, i);
                NeoDatis.Odb.Core.Layers.Layer2.Meta.ClassInfo ci = null;
                if (o != null)
                {
                    ci = GetClassInfo(OdbClassUtil.GetFullName(o.GetType()));
                    NeoDatis.Odb.Core.Layers.Layer2.Meta.AbstractObjectInfo aoi = GetObjectInfo(o, ci
                                                                                                , introspect, alreadyReadObjects, callback);
                    arrayCopy[i] = aoi;
                }
                else
                {
                    arrayCopy[i] = new NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeNullObjectInfo();
                }
            }
            NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo arrayOfAoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo
                                                                                  (arrayCopy, valueType, type.GetId());
            return(arrayOfAoi);
        }
        /// <summary>
        /// Build a meta representation of an object
        /// <pre>
        /// warning: When an object has two fields with the same name (a private field with the same name in a parent class, the deeper field (of the parent) is ignored!)
        /// </pre>
        /// </summary>
        /// <param name="o"></param>
        /// <param name="ci"></param>
        /// <param name="recursive"></param>
        /// <returns>The ObjectInfo</returns>
        protected virtual NeoDatis.Odb.Core.Layers.Layer2.Meta.AbstractObjectInfo GetObjectInfoInternal
            (NeoDatis.Odb.Core.Layers.Layer2.Meta.AbstractObjectInfo nnoi, object o, NeoDatis.Odb.Core.Layers.Layer2.Meta.ClassInfo
            ci, bool recursive, System.Collections.Generic.IDictionary <object, NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeObjectInfo
                                                                        > alreadyReadObjects, NeoDatis.Odb.Core.Layers.Layer1.Introspector.IIntrospectionCallback
            callback)
        {
            object value = null;

            if (o == null)
            {
                return(NeoDatis.Odb.Core.Layers.Layer2.Meta.NullNativeObjectInfo.GetInstance());
            }
            System.Type clazz = o.GetType();
            NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType type = NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType
                                                                .GetFromClass(clazz);
            string className = OdbClassUtil.GetFullName(clazz);

            if (type.IsNative())
            {
                return(GetNativeObjectInfoInternal(type, o, recursive, alreadyReadObjects,
                                                   callback));
            }
            // sometimes the clazz.getName() may not match the ci.getClassName()
            // It happens when the attribute is an interface or superclass of the
            // real attribute class
            // In this case, ci must be updated to the real class info
            if (ci != null && !clazz.FullName.Equals(ci.GetFullClassName()))
            {
                ci   = GetClassInfo(className);
                nnoi = null;
            }
            NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeObjectInfo mainAoi = (NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeObjectInfo
                                                                                )nnoi;
            bool isRootObject = false;

            if (alreadyReadObjects == null)
            {
                alreadyReadObjects = new NeoDatis.Tool.Wrappers.Map.OdbHashMap <object, NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeObjectInfo
                                                                                >();
                isRootObject = true;
            }
            if (o != null)
            {
                NonNativeObjectInfo cachedNnoi = null;
                alreadyReadObjects.TryGetValue(o, out cachedNnoi);

                if (cachedNnoi != null)
                {
                    ObjectReference or = new ObjectReference(cachedNnoi);
                    return(or);
                }
                if (callback != null)
                {
                    callback.ObjectFound(o);
                }
            }
            if (mainAoi == null)
            {
                mainAoi = BuildNnoi(o, ci, null, null, null, alreadyReadObjects);
            }
            alreadyReadObjects[o] = mainAoi;
            NeoDatis.Tool.Wrappers.List.IOdbList <System.Reflection.FieldInfo> fields = classIntrospector.GetAllFields(className);
            NeoDatis.Odb.Core.Layers.Layer2.Meta.AbstractObjectInfo            aoi    = null;
            int attributeId = -1;

            // For all fields
            for (int i = 0; i < fields.Count; i++)
            {
                System.Reflection.FieldInfo field = fields[i];
                try
                {
                    value       = field.GetValue(o);
                    attributeId = ci.GetAttributeId(field.Name);
                    if (attributeId == -1)
                    {
                        throw new ODBRuntimeException(NeoDatisError.ObjectIntrospectorNoFieldWithName.AddParameter(ci.GetFullClassName()).AddParameter(field.Name));
                    }
                    ODBType valueType = null;
                    if (value == null)
                    {
                        // If value is null, take the type from the field type
                        // declared in the class
                        valueType = ODBType.GetFromClass(field.FieldType);
                    }
                    else
                    {
                        // Else take the real attribute type!
                        valueType = ODBType.GetFromClass(value.GetType());
                    }
                    // for native fields
                    if (valueType.IsNative())
                    {
                        aoi = GetNativeObjectInfoInternal(valueType, value, recursive, alreadyReadObjects, callback);
                        mainAoi.SetAttributeValue(attributeId, aoi);
                    }
                    else
                    {
                        //callback.objectFound(value);
                        // Non Native Objects
                        if (value == null)
                        {
                            ClassInfo clai = GetClassInfo(OdbClassUtil.GetFullName(field.GetType()));

                            aoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeNullObjectInfo(clai);
                            mainAoi.SetAttributeValue(attributeId, aoi);
                        }
                        else
                        {
                            ClassInfo clai = GetClassInfo(OdbClassUtil.GetFullName(value.GetType()));
                            if (recursive)
                            {
                                aoi = GetObjectInfoInternal(null, value, clai, recursive, alreadyReadObjects, callback
                                                            );
                                mainAoi.SetAttributeValue(attributeId, aoi);
                            }
                            else
                            {
                                // When it is not recursive, simply add the object
                                // values.add(value);
                                throw new NeoDatis.Odb.ODBRuntimeException(NeoDatis.Odb.Core.NeoDatisError.InternalError
                                                                           .AddParameter("Should not enter here - ObjectIntrospector - 'simply add the object'"
                                                                                         ));
                            }
                        }
                    }
                }
                catch (System.ArgumentException e)
                {
                    throw new NeoDatis.Odb.ODBRuntimeException(NeoDatis.Odb.Core.NeoDatisError.InternalError
                                                               .AddParameter("in getObjectInfoInternal"), e);
                }
                catch (System.MemberAccessException e)
                {
                    throw new NeoDatis.Odb.ODBRuntimeException(NeoDatis.Odb.Core.NeoDatisError.InternalError
                                                               .AddParameter("getObjectInfoInternal"), e);
                }
            }
            if (isRootObject)
            {
                alreadyReadObjects.Clear();
                alreadyReadObjects = null;
            }
            return(mainAoi);
        }
		/// <summary>
		/// Build a meta representation of an object
		/// <pre>
		/// warning: When an object has two fields with the same name (a private field with the same name in a parent class, the deeper field (of the parent) is ignored!)
		/// </pre>
		/// </summary>
		/// <param name="o"></param>
		/// <param name="ci"></param>
		/// <param name="recursive"></param>
		/// <returns>The ObjectInfo</returns>
		protected virtual NeoDatis.Odb.Core.Layers.Layer2.Meta.AbstractObjectInfo GetObjectInfoInternal
			(NeoDatis.Odb.Core.Layers.Layer2.Meta.AbstractObjectInfo nnoi, object o, NeoDatis.Odb.Core.Layers.Layer2.Meta.ClassInfo
			 ci, bool recursive, System.Collections.Generic.IDictionary<object, NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeObjectInfo
			> alreadyReadObjects, NeoDatis.Odb.Core.Layers.Layer1.Introspector.IIntrospectionCallback
			 callback)
		{
			object value = null;
			if (o == null)
			{
				return NeoDatis.Odb.Core.Layers.Layer2.Meta.NullNativeObjectInfo.GetInstance();
			}
			System.Type clazz = o.GetType();
			NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType type = NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType
				.GetFromClass(clazz);
			string className = OdbClassUtil.GetFullName(clazz);
			if (type.IsNative())
			{
				return GetNativeObjectInfoInternal(type, o, recursive, alreadyReadObjects, 
					callback);
			}
			// sometimes the clazz.getName() may not match the ci.getClassName()
			// It happens when the attribute is an interface or superclass of the
			// real attribute class
			// In this case, ci must be updated to the real class info
			if (ci != null && !clazz.FullName.Equals(ci.GetFullClassName()))
			{
				ci = GetClassInfo(className);
				nnoi = null;
			}
			NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeObjectInfo mainAoi = (NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeObjectInfo
				)nnoi;
			bool isRootObject = false;
			if (alreadyReadObjects == null)
			{
				alreadyReadObjects = new NeoDatis.Tool.Wrappers.Map.OdbHashMap<object, NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeObjectInfo
					>();
				isRootObject = true;
			}
			if (o != null)
			{
                NonNativeObjectInfo cachedNnoi = null;
                alreadyReadObjects.TryGetValue(o, out cachedNnoi);
				
                if (cachedNnoi != null)
				{
					ObjectReference or = new ObjectReference(cachedNnoi);
					return or;
				}
				if (callback != null)
				{
					callback.ObjectFound(o);
				}
			}
			if (mainAoi == null)
			{
				mainAoi = BuildNnoi(o, ci, null, null, null, alreadyReadObjects);
			}
			alreadyReadObjects[o] = mainAoi;
			NeoDatis.Tool.Wrappers.List.IOdbList<System.Reflection.FieldInfo> fields = classIntrospector.GetAllFields(className);
			NeoDatis.Odb.Core.Layers.Layer2.Meta.AbstractObjectInfo aoi = null;
			int attributeId = -1;
			// For all fields
			for (int i = 0; i < fields.Count; i++)
			{
				System.Reflection.FieldInfo field = fields[i];
				try
				{
					value = field.GetValue(o);
					attributeId = ci.GetAttributeId(field.Name);
					if (attributeId == -1)
					{
						throw new ODBRuntimeException(NeoDatisError.ObjectIntrospectorNoFieldWithName.AddParameter(ci.GetFullClassName()).AddParameter(field.Name));
					}
					ODBType valueType = null;
					if (value == null)
					{
						// If value is null, take the type from the field type
						// declared in the class
						valueType = ODBType.GetFromClass(field.FieldType);
					}
					else
					{
						// Else take the real attribute type!
						valueType = ODBType.GetFromClass(value.GetType());
					}
					// for native fields
					if (valueType.IsNative())
					{
						aoi = GetNativeObjectInfoInternal(valueType, value, recursive, alreadyReadObjects, callback);
						mainAoi.SetAttributeValue(attributeId, aoi);
					}
					else
					{
						//callback.objectFound(value);
						// Non Native Objects
						if (value == null)
						{
                            ClassInfo clai = GetClassInfo(OdbClassUtil.GetFullName(field.GetType()));

							aoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeNullObjectInfo(clai);
							mainAoi.SetAttributeValue(attributeId, aoi);
						}
						else
						{
                            ClassInfo clai = GetClassInfo(OdbClassUtil.GetFullName(value.GetType()));
							if (recursive)
							{
								aoi = GetObjectInfoInternal(null, value, clai, recursive, alreadyReadObjects, callback
									);
								mainAoi.SetAttributeValue(attributeId, aoi);
							}
							else
							{
								// When it is not recursive, simply add the object
								// values.add(value);
								throw new NeoDatis.Odb.ODBRuntimeException(NeoDatis.Odb.Core.NeoDatisError.InternalError
									.AddParameter("Should not enter here - ObjectIntrospector - 'simply add the object'"
									));
							}
						}
					}
				}
				catch (System.ArgumentException e)
				{
					throw new NeoDatis.Odb.ODBRuntimeException(NeoDatis.Odb.Core.NeoDatisError.InternalError
						.AddParameter("in getObjectInfoInternal"), e);
				}
				catch (System.MemberAccessException e)
				{
					throw new NeoDatis.Odb.ODBRuntimeException(NeoDatis.Odb.Core.NeoDatisError.InternalError
						.AddParameter("getObjectInfoInternal"), e);
				}
			}
			if (isRootObject)
			{
				alreadyReadObjects.Clear();
				alreadyReadObjects = null;
			}
			return mainAoi;
		}
		private NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo IntrospectArray(object
			 array, bool introspect, System.Collections.Generic.IDictionary<object, NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeObjectInfo
			> alreadyReadObjects, NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType valueType, NeoDatis.Odb.Core.Layers.Layer1.Introspector.IIntrospectionCallback
			 callback)
		{
			int length = NeoDatis.Tool.Wrappers.OdbReflection.GetArrayLength(array);
			System.Type elementType = array.GetType().GetElementType();
			NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType type = NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType
				.GetFromClass(elementType);
			if (type.IsAtomicNative())
			{
				return IntropectAtomicNativeArray(array, type);
			}
			if (!introspect)
			{
				return new NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo((object[])array);
			}
			object[] arrayCopy = new object[length];
			for (int i = 0; i < length; i++)
			{
				object o = NeoDatis.Tool.Wrappers.OdbReflection.GetArrayElement(array, i);
				NeoDatis.Odb.Core.Layers.Layer2.Meta.ClassInfo ci = null;
				if (o != null)
				{
					ci = GetClassInfo(OdbClassUtil.GetFullName(o.GetType()));
					NeoDatis.Odb.Core.Layers.Layer2.Meta.AbstractObjectInfo aoi = GetObjectInfo(o, ci
						, introspect, alreadyReadObjects, callback);
					arrayCopy[i] = aoi;
				}
				else
				{
					arrayCopy[i] = new NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeNullObjectInfo();
				}
			}
			NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo arrayOfAoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo
				(arrayCopy, valueType, type.GetId());
			return arrayOfAoi;
		}
		public virtual NeoDatis.Odb.OID WriteNonNativeObjectInfo(NeoDatis.Odb.OID existingOid
			, NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeObjectInfo objectInfo, long position
			, bool writeDataInTransaction, bool isNewObject)
		{
			NeoDatis.Odb.Core.Transaction.ISession lsession = GetSession();
			NeoDatis.Odb.Core.Transaction.ICache cache = lsession.GetCache();
			bool hasObject = objectInfo.GetObject() != null;
			// Insert triggers for CS Mode, local mode insert triggers are called in the DefaultInstrumentationCallbackForStore class
			if (isNewObject && !isLocalMode)
			{
				triggerManager.ManageInsertTriggerBefore(objectInfo.GetClassInfo().GetFullClassName
					(), objectInfo);
			}
			// Checks if object is null,for null objects,there is nothing to do
			if (objectInfo.IsNull())
			{
				return NeoDatis.Odb.Impl.Core.Layers.Layer3.Engine.StorageEngineConstant.NullObjectId;
			}
			NeoDatis.Odb.Core.Layers.Layer2.Meta.MetaModel metaModel = lsession.GetMetaModel(
				);
			// first checks if the class of this object already exist in the
			// metamodel
			if (!metaModel.ExistClass(objectInfo.GetClassInfo().GetFullClassName()))
			{
				AddClass(objectInfo.GetClassInfo(), true);
			}
			// if position is -1, gets the position where to write the object
			if (position == -1)
			{
				// Write at the end of the file
				position = fsi.GetAvailablePosition();
				// Updates the meta object position
				objectInfo.SetPosition(position);
			}
			// Gets the object id
			NeoDatis.Odb.OID oid = existingOid;
			if (oid == null)
			{
				// If, to get the next id, a new id block must be created, then
				// there is an extra work
				// to update the current object position
				if (idManager.MustShift())
				{
					oid = idManager.GetNextObjectId(position);
					// The id manager wrote in the file so the position for the
					// object must be re-computed
					position = fsi.GetAvailablePosition();
					// The oid must be associated to this new position - id
					// operations are always out of transaction
					// in this case, the update is done out of the transaction as a
					// rollback won t need to
					// undo this. We are just creating the id
					// => third parameter(write in transaction) = false
					idManager.UpdateObjectPositionForOid(oid, position, false);
				}
				else
				{
					oid = idManager.GetNextObjectId(position);
				}
			}
			else
			{
				// If an oid was passed, it is because object already exist and
				// is being updated. So we
				// must update the object position
				// Here the update of the position of the id must be done in
				// transaction as the object
				// position of the id is being updated, and a rollback should undo
				// this
				// => third parameter(write in transaction) = true
				idManager.UpdateObjectPositionForOid(oid, position, true);
				// Keep the relation of id and position in the cache until the
				// commit
				cache.SavePositionOfObjectWithOid(oid, position);
			}
			// Sets the oid of the object in the inserting cache
			cache.UpdateIdOfInsertingObject(objectInfo.GetObject(), oid);
			// Only add the oid to unconnected zone if it is a new object
			if (isNewObject)
			{
				cache.AddOIDToUnconnectedZone(oid);
				if (NeoDatis.Odb.OdbConfiguration.ReconnectObjectsToSession())
				{
					NeoDatis.Odb.Core.Transaction.ICrossSessionCache crossSessionCache = NeoDatis.Odb.Impl.Core.Transaction.CacheFactory
						.GetCrossSessionCache(storageEngine.GetBaseIdentification().GetIdentification());
					crossSessionCache.AddObject(objectInfo.GetObject(), oid);
				}
			}
			objectInfo.SetOid(oid);
			if (NeoDatis.Odb.OdbConfiguration.IsDebugEnabled(LogId))
			{
				NeoDatis.Tool.DLogger.Debug(DepthToSpaces() + "Start Writing non native object of type "
					 + objectInfo.GetClassInfo().GetFullClassName() + " at " + position + " , oid = "
					 + oid + " : " + objectInfo.ToString());
			}
			if (objectInfo.GetClassInfo() == null || objectInfo.GetClassInfo().GetId() == null)
			{
				if (objectInfo.GetClassInfo() != null)
				{
					NeoDatis.Odb.Core.Layers.Layer2.Meta.ClassInfo clinfo = storageEngine.GetSession(
						true).GetMetaModel().GetClassInfo(objectInfo.GetClassInfo().GetFullClassName(), 
						true);
					objectInfo.SetClassInfo(clinfo);
				}
				else
				{
					throw new NeoDatis.Odb.ODBRuntimeException(NeoDatis.Odb.Core.NeoDatisError.UndefinedClassInfo
						.AddParameter(objectInfo.ToString()));
				}
			}
			// updates the meta model - If class already exist, it returns the
			// metamodel class, which contains
			// a bit more informations
			NeoDatis.Odb.Core.Layers.Layer2.Meta.ClassInfo classInfo = AddClass(objectInfo.GetClassInfo
				(), true);
			objectInfo.SetClassInfo(classInfo);
			// 
			if (isNewObject)
			{
				ManageNewObjectPointers(objectInfo, classInfo, position, metaModel);
			}
			if (NeoDatis.Odb.OdbConfiguration.SaveHistory())
			{
				classInfo.AddHistory(new NeoDatis.Odb.Impl.Core.Layers.Layer2.Meta.History.InsertHistoryInfo
					("insert", oid, position, objectInfo.GetPreviousObjectOID(), objectInfo.GetNextObjectOID
					()));
			}
			fsi.SetWritePosition(position, writeDataInTransaction);
			objectInfo.SetPosition(position);
			int nbAttributes = objectInfo.GetClassInfo().GetAttributes().Count;
			// compute the size of the array of byte needed till the attibute
			// positions
			// BlockSize + Block Type + ObjectId + ClassInfoId + Previous + Next +
			// CreatDate + UpdateDate + VersionNumber + ObjectRef + isSync + NbAttri
			// + Attributes
			// Int + Int + Long + Long + Long + Long + Long + Long + int + Long +
			// Bool + int + variable
			// 7 Longs + 4Ints + 1Bool + variable
			int tsize = 7 * NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType.SizeOfLong + 3 * NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType
				.SizeOfInt + 2 * NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType.SizeOfByte;
			byte[] bytes = new byte[tsize];
			// Block size
			byteArrayConverter.IntToByteArray(0, bytes, 0);
			// Block type
			bytes[4] = NeoDatis.Odb.Impl.Core.Layers.Layer3.Block.BlockTypes.BlockTypeNonNativeObject;
			// fsi.writeInt(BlockTypes.BLOCK_TYPE_NON_NATIVE_OBJECT,
			// writeDataInTransaction, "block size");
			// The object id
			EncodeOid(oid, bytes, 5);
			// fsi.writeLong(oid.getObjectId(), writeDataInTransaction, "oid",
			// DefaultWriteAction.DATA_WRITE_ACTION);
			// Class info id
			byteArrayConverter.LongToByteArray(classInfo.GetId().GetObjectId(), bytes, 13);
			// fsi.writeLong(classInfo.getId().getObjectId(),
			// writeDataInTransaction, "class info id",
			// DefaultWriteAction.DATA_WRITE_ACTION);
			// previous instance
			EncodeOid(objectInfo.GetPreviousObjectOID(), bytes, 21);
			// writeOid(objectInfo.getPreviousObjectOID(), writeDataInTransaction,
			// "prev instance", DefaultWriteAction.DATA_WRITE_ACTION);
			// next instance
			EncodeOid(objectInfo.GetNextObjectOID(), bytes, 29);
			// writeOid(objectInfo.getNextObjectOID(), writeDataInTransaction,
			// "next instance", DefaultWriteAction.DATA_WRITE_ACTION);
			// creation date, for update operation must be the original one
			byteArrayConverter.LongToByteArray(objectInfo.GetHeader().GetCreationDate(), bytes
				, 37);
			// fsi.writeLong(objectInfo.getHeader().getCreationDate(),
			// writeDataInTransaction, "creation date",
			// DefaultWriteAction.DATA_WRITE_ACTION);
			byteArrayConverter.LongToByteArray(NeoDatis.Tool.Wrappers.OdbTime.GetCurrentTimeInMs
				(), bytes, 45);
			// fsi.writeLong(OdbTime.getCurrentTimeInMs(), writeDataInTransaction,
			// "update date", DefaultWriteAction.DATA_WRITE_ACTION);
			// TODO check next version number
			byteArrayConverter.IntToByteArray(objectInfo.GetHeader().GetObjectVersion(), bytes
				, 53);
			// fsi.writeInt(objectInfo.getHeader().getObjectVersion(),
			// writeDataInTransaction, "object version number");
			// not used yet. But it will point to an internal object of type
			// ObjectReference that will have details on the references:
			// All the objects that point to it: to enable object integrity
			byteArrayConverter.LongToByteArray(-1, bytes, 57);
			// fsi.writeLong(-1, writeDataInTransaction, "object reference pointer",
			// DefaultWriteAction.DATA_WRITE_ACTION);
			// True if this object have been synchronized with main database, else
			// false
			byteArrayConverter.BooleanToByteArray(false, bytes, 65);
			// fsi.writeBoolean(false, writeDataInTransaction,
			// "is syncronized with external db");
			// now write the number of attributes and the position of all
			// attributes, we do not know them yet, so write 00 but at the end
			// of the write operation
			// These positions will be updated
			// The positions that is going to be written are 'int' representing
			// the offset position of the attribute
			// first write the number of attributes
			// fsi.writeInt(nbAttributes, writeDataInTransaction, "nb attr");
			byteArrayConverter.IntToByteArray(nbAttributes, bytes, 66);
			// Then write the array of bytes
			fsi.WriteBytes(bytes, writeDataInTransaction, "NonNativeObjectInfoHeader");
			// Store the position
			long attributePositionStart = fsi.GetPosition();
			int attributeSize = NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType.SizeOfInt + NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType
				.SizeOfLong;
			byte[] abytes = new byte[nbAttributes * (attributeSize)];
			// here, just write an empty (0) array, as real values will be set at
			// the end
			fsi.WriteBytes(abytes, writeDataInTransaction, "Empty Attributes");
			long[] attributesIdentification = new long[nbAttributes];
			int[] attributeIds = new int[nbAttributes];
			// Puts the object info in the cache
			// storageEngine.getSession().getCache().addObject(position,
			// aoi.getObject(), objectInfo.getHeader());
			NeoDatis.Odb.Core.Layers.Layer2.Meta.ClassAttributeInfo cai = null;
			NeoDatis.Odb.Core.Layers.Layer2.Meta.AbstractObjectInfo aoi2 = null;
			long nativeAttributePosition = -1;
			NeoDatis.Odb.OID nonNativeAttributeOid = null;
			long maxWritePosition = fsi.GetPosition();
			// Loop on all attributes
			for (int i = 0; i < nbAttributes; i++)
			{
				// Gets the attribute meta description
				cai = classInfo.GetAttributeInfo(i);
				// Gets the id of the attribute
				attributeIds[i] = cai.GetId();
				// Gets the attribute data
				aoi2 = objectInfo.GetAttributeValueFromId(cai.GetId());
				if (aoi2 == null)
				{
					// This only happens in 1 case : when a class has a field with
					// the same name of one of is superclass. In this, the deeper
					// attribute is null
					if (cai.IsNative())
					{
						aoi2 = new NeoDatis.Odb.Core.Layers.Layer2.Meta.NullNativeObjectInfo(cai.GetAttributeType
							().GetId());
					}
					else
					{
						aoi2 = new NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeNullObjectInfo(cai.GetClassInfo
							());
					}
				}
				if (aoi2.IsNative())
				{
					nativeAttributePosition = InternalStoreObject((NeoDatis.Odb.Core.Layers.Layer2.Meta.NativeObjectInfo
						)aoi2);
					// For native objects , odb stores their position
					attributesIdentification[i] = nativeAttributePosition;
				}
				else
				{
					if (aoi2.IsObjectReference())
					{
						NeoDatis.Odb.Core.Layers.Layer2.Meta.ObjectReference or = (NeoDatis.Odb.Core.Layers.Layer2.Meta.ObjectReference
							)aoi2;
						nonNativeAttributeOid = or.GetOid();
					}
					else
					{
						nonNativeAttributeOid = StoreObject(null, (NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeObjectInfo
							)aoi2);
					}
					// For non native objects , odb stores its oid as a negative
					// number!!u
					if (nonNativeAttributeOid != null)
					{
						attributesIdentification[i] = -nonNativeAttributeOid.GetObjectId();
					}
					else
					{
						attributesIdentification[i] = NeoDatis.Odb.Impl.Core.Layers.Layer3.Engine.StorageEngineConstant
							.NullObjectIdId;
					}
				}
				long p = fsi.GetPosition();
				if (p > maxWritePosition)
				{
					maxWritePosition = p;
				}
			}
			// Updates attributes identification in the object info header
			objectInfo.GetHeader().SetAttributesIdentification(attributesIdentification);
			objectInfo.GetHeader().SetAttributesIds(attributeIds);
			long positionAfterWrite = maxWritePosition;
			// Now writes back the attribute positions
			fsi.SetWritePosition(attributePositionStart, writeDataInTransaction);
			abytes = new byte[attributesIdentification.Length * (attributeSize)];
			for (int i = 0; i < attributesIdentification.Length; i++)
			{
				byteArrayConverter.IntToByteArray(attributeIds[i], abytes, i * attributeSize);
				byteArrayConverter.LongToByteArray(attributesIdentification[i], abytes, i * (attributeSize
					) + NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType.SizeOfInt);
				// fsi.writeInt(attributeIds[i], writeDataInTransaction, "attr id");
				// fsi.writeLong(attributesIdentification[i],
				// writeDataInTransaction, "att real pos",
				// DefaultWriteAction.DATA_WRITE_ACTION);
				// if (classInfo.getAttributeInfo(i).isNonNative() &&
				// attributesIdentification[i] > 0) {
				if (objectInfo.GetAttributeValueFromId(attributeIds[i]).IsNonNativeObject() && attributesIdentification
					[i] > 0)
				{
					throw new NeoDatis.Odb.ODBRuntimeException(NeoDatis.Odb.Core.NeoDatisError.NonNativeAttributeStoredByPositionInsteadOfOid
						.AddParameter(classInfo.GetAttributeInfo(i).GetName()).AddParameter(classInfo.GetFullClassName
						()).AddParameter(attributesIdentification[i]));
				}
			}
			fsi.WriteBytes(abytes, writeDataInTransaction, "Filled Attributes");
			fsi.SetWritePosition(positionAfterWrite, writeDataInTransaction);
			int blockSize = (int)(positionAfterWrite - position);
			try
			{
				WriteBlockSizeAt(position, blockSize, writeDataInTransaction, objectInfo);
			}
			catch (NeoDatis.Odb.ODBRuntimeException e)
			{
				NeoDatis.Tool.DLogger.Debug("Error while writing block size. pos after write " + 
					positionAfterWrite + " / start pos = " + position);
				// throw new ODBRuntimeException(storageEngine,"Error while writing
				// block size. pos after write " + positionAfterWrite + " / start
				// pos = " + position,e);
				throw;
			}
			if (NeoDatis.Odb.OdbConfiguration.IsDebugEnabled(LogId))
			{
				NeoDatis.Tool.DLogger.Debug(DepthToSpaces() + "  Attributes positions of object with oid "
					 + oid + " are " + NeoDatis.Tool.DisplayUtility.LongArrayToString(attributesIdentification
					));
				NeoDatis.Tool.DLogger.Debug(DepthToSpaces() + "End Writing non native object at "
					 + position + " with oid " + oid + " - prev oid=" + objectInfo.GetPreviousObjectOID
					() + " / next oid=" + objectInfo.GetNextObjectOID());
				if (NeoDatis.Odb.OdbConfiguration.IsDebugEnabled(LogIdDebug))
				{
					NeoDatis.Tool.DLogger.Debug(" - current buffer : " + fsi.GetIo().ToString());
				}
			}
			// Only insert in index for new objects
			if (isNewObject)
			{
				// insert object id in indexes, if exist
				ManageIndexesForInsert(oid, objectInfo);
				if (hasObject)
				{
					triggerManager.ManageInsertTriggerAfter(objectInfo.GetClassInfo().GetFullClassName
						(), objectInfo.GetObject(), oid);
				}
				else
				{
					// triggers
					triggerManager.ManageInsertTriggerAfter(objectInfo.GetClassInfo().GetFullClassName
						(), objectInfo, oid);
				}
			}
			return oid;
		}