commsfwtools/preparedefaultcommsdatabase/src/CommsDatMapper.cpp
changeset 0 dfb7c4ff071f
child 12 8b5d60ce1e94
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/commsfwtools/preparedefaultcommsdatabase/src/CommsDatMapper.cpp	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,2258 @@
+// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Mapping rules for deprecated elements in the comms database schema
+// All data in file
+// CONTENTS OF FILE
+// 1/  Utilities
+// 2/  CCDMapper Base class implementation
+// 3/  Mapper classes for individual elements in the database
+// a) CCDMapperGlobalSettingsRecord
+// b) CCDMapperIAPPrioritySelectionPolicyRecord
+// c) CCDMapperAccessPointRecord
+// MAINTENANCE - some rules may need adding or amending whenever the database schema changes
+// 
+//
+
+/**
+ @file CommsDatMapper.cpp
+ @internalComponent
+*/
+
+
+#include "CommsDatInternalDefs.h"
+#include <commsdattypesv1_1.h>
+#include "CommsDatMapper.h"
+#include <comms-infras/commsdatschema.h>
+#include <commsdat.h>
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <commsdattypesv1_1_partner.h>
+#include <commsdat_partner.h>
+#endif
+
+using namespace Meta;
+using namespace CommsDatInternal;
+using namespace CommsDat;
+
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY 
+//anonymous namespace
+namespace
+    {
+    const TInt NetworkBaseTagId     = 10000;
+    }
+#endif //SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY 
+/***************************************************************************************
+ * 1/ Utilities
+ */
+
+
+
+TBool Changed(const CMDBElement& aElement)
+/*
+Utility function to check if an element has been changed
+@internalComponent
+*/
+    {
+    if ( aElement.ElementId() & KCDChangedFlag )
+        {
+        return ETrue;
+        }
+
+    return EFalse;
+    }
+    
+
+void Sync(CMDBElement& aElement)
+/*
+Utility function to mark an element in sync with Database
+@internalComponent
+*/
+    {
+    aElement.SetElementId(aElement.ElementId() & ~KCDChangedFlag);
+    }
+
+
+
+TInt CCDMapper::FindLinkElementIdL(TInt aVal, TInt aTargetTable)
+/*
+utility for mapping link fields - when link fields fixed this will be unnecessary
+*/    {
+        TInt ret(KErrNone);
+
+        if (KLinkableTag & aVal)
+            {
+            // this is a link by tag so need to do a find for the tag in the target field
+            CMDBField<TUint32>* tagField = new (ELeave) CMDBField<TUint32>(aTargetTable |KCDTIdRecordTag);
+            CleanupStack::PushL(tagField);
+
+            *tagField = aVal;
+
+            if (tagField->FindL(iSession.iOwner))
+                {
+                ret = (tagField->ElementId() | KCDMaskShowRecordTypeAndId);
+                }
+
+            CleanupStack::PopAndDestroy(tagField);
+       
+            }
+
+        // add a check for the record id too.
+           
+        // otherwise the value already gives the element id directly
+
+        return ret;
+        }   
+
+
+/****************************************************************************************
+ * 2/  CCDMapper base class implementation
+ ***************************************************************************************/
+  
+CCDMapper::CCDMapper(TMDBElementId aElementId, CMDBElement& aElement,CMDBSessionImpl& aSession
+		             ,const TOperation& aOperation)
+	: CMDBRecordBase(aElementId)
+    , iElement(aElement)
+    , iSession(aSession)
+    , iOperation(aOperation)
+    {
+    iSession.iMapping = ETrue;
+    }
+
+        
+CCDMapper::~CCDMapper()
+    {
+    iSession.iMapping = EFalse;
+    }
+ 
+   
+
+CCDMapper* CCDMapper::MaybeCreateMapperLC(CMDBElement& aElement,CMDBSessionImpl& aSession, const TOperation& aOperation)
+/*
+Static Factory function. 
+
+  Creates a mapping object of the appropriate type
+
+@internalComponent
+*/
+	{
+    if (aSession.UsingLatestVersion() || aSession.iMapping)
+        {
+        // only map if client has asked to manage deprecated fields
+        // and if no mapping or validation going on already
+        return NULL;
+        }
+
+    if(CommsDat::CommsDatSchema::IsTable(aElement.ElementId()))
+        {
+    	// only need mapper for records and fields, not tables
+        return NULL;
+        }
+
+	CCDMapper* mapper = NULL;
+    
+    switch((TUint32)aElement.TypeId() & KCDMaskShowRecordType)
+	    {
+
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+	    
+        case KCDTIdGlobalSettingsRecord:
+	        {
+            mapper = new(ELeave)CCDMapperGlobalSettingsRecord(aElement,aSession, aOperation); 
+		    break;
+	        }
+           
+	    case KCDTIdIapPrioritySelectionPolicyRecord:
+	        {
+            mapper = new(ELeave)CCDMapperIAPPrioritySelectionPolicyRecord(aElement,aSession, aOperation); 
+            break;
+	        }
+            
+	    case KCDTIdAccessPointRecord:
+	        {
+	        mapper = new(ELeave)CCDMapperAccessPointRecord(aElement,aSession, aOperation); 
+		    break;
+	        }
+
+#endif // SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+        
+        default :
+            {
+            // Nothing to do so exit quickly
+            mapper = NULL;
+            }
+		}
+
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+
+    if(! mapper)
+        {
+        return NULL;
+        }
+        
+    if (mapper->NeedsMapping(aElement))
+        {
+       
+        CleanupStack::PushL(mapper);
+        mapper->ConstructL();
+        }
+    else 
+        {
+        delete mapper;
+        mapper = NULL;
+        }
+
+#endif // SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+
+    return mapper;	
+	}
+
+   
+   
+
+void CCDMapper::ConstructL()
+/*
+following a unique set of mapping rules implemented in derived classes and
+using information from both the input element and the database
+1/ Set up record id(s) for elements in the map 
+2/ where deprecated elements in the input element (iElement) have values that
+have been changed by the user, populate the values of the corresponding map element(s) 
+@internalTechnology
+*/
+    {   
+    //  Default is nothing to construct
+    return;
+    }
+    
+void CCDMapper::PrepareToStoreL()
+    {   
+    //  Default is nothing to prepare
+    return;
+    }
+
+
+//TBool CCDMapper::Mapped(TMDBElementId aElementId)
+/*
+Return ETrue if the sub-element (always a field) is mapped.  
+Otherwise return EFalse
+
+@internalTechnology
+*/
+   // {
+  //  return aElementId != aElementId;
+   // }
+
+
+void CCDMapper::MapResultsL()
+/*
+Set up record id(s) for the map and populate each entry in the map
+following a unique set of mapping rules (implemented in derived classes)
+using information from both the input element and the database
+
+@internalTechnology
+*/
+    { 
+    // Default is nothing to map
+    return; 
+    }
+    
+/*virtual*/ void CCDMapper::PostMappingsL()
+/*
+@internalTechnology
+*/    
+    {
+     // Default is nothing to process...
+    (void)iOperation; //just to bypass the comp. warning
+    return; 
+    }
+
+/*virtual*/ void CCDMapper::PreMappingsL()
+/*
+@internalTechnology
+*/    
+    {
+     // Default is nothing to process...
+    (void)iOperation; //just to bypass the comp. warning
+    return; 
+    }
+
+/*****************************************************************************************
+ * 3/ MAPPER CLASSES FOR INDIVIDUAL ELEMENTS
+ *****************************************************************************************/
+     
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY 
+
+/************************* 3/ a) Mapper for GlobalSettings Table ************************************
+ * KCDTIdGlobalSettingsRecord
+ *
+ * These 2 fields are now stored against the Default Tier record in the Tier table
+ *      DefaultSnap     KCDTIdDefaultSnap    CCDGlobalSettingsRecord::iDefaultSnap
+ *      PromptUser      KCDTIdPromptForSnap  CCDGlobalSettingsRecord::iPromptForSnap
+ *
+ * Corresponding fields in the Tier table (KCDTIdTierRecord) are
+ *      DefaultSnap     KCDTIdDefaultAccessPoint  CCDTierRecord::iDefaultAccessPoint
+ *	    PromptUser      KCDTIdPromptUser          CCDTierRecord::iPromptUser
+ *
+ * The mapping relies on the presence of the DefaultTier field in the GlobalSettings Table
+ *      DefaultTier     KCDTIdDefaultTier    CCDGlobalSettingsRecord::iDefaultTier
+ *
+ * The DefaultTier must always be present as a real or default value in the GlobalSettings
+ * Table.  A preface config file may be the best way to set this value.
+ * 
+ * If KCDTIdDefaultTier field is not present in the GlobalSettings Table, 
+ * these fields cannot be mapped [They could be set as default values in Template of Tier Table?]
+ */
+#define KCDTIdGlobalSettingsRecordMapper    9879
+START_ATTRIBUTE_TABLE( CCDMapperGlobalSettingsRecord, KCDTIdGlobalSettingsRecordMapper, KCDTIdGlobalSettingsRecordMapper)
+	X_REGISTER_ATTRIBUTE( CCDMapperGlobalSettingsRecord, iPromptUser,         TMDBNum)
+    //X_REGISTER_ATTRIBUTE( CCDMapperGlobalSettingsRecord, iDefaultAccessPoint, TMDBNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperGlobalSettingsRecord, iDefaultAccessPoint, TMDBLinkNum)
+END_ATTRIBUTE_TABLE()
+
+CCDMapperGlobalSettingsRecord::CCDMapperGlobalSettingsRecord(CMDBElement& aElement,CMDBSessionImpl& aSession, const TOperation& aOperation)
+: CCDMapper(0, aElement,aSession,aOperation), 	
+  iPromptUser(KCDTIdPromptUser),
+  iDefaultAccessPoint(KCDTIdDefaultAccessPoint)		
+    {}
+
+
+void CCDMapperGlobalSettingsRecord::ConstructL()
+/*
+Set up record id(s) for elements in the map and populate the values of 
+each each element in the map following a unique set of mapping rules 
+(implemented in derived classes) using information from both the input 
+element and the database
+
+ * Rules 
+    a) find DefaultTier in GlobalSettings record (from inputElement or database)
+    b) use the value to give the record id of the Tier record
+
+@internalComponent
+*/
+    {   
+    CMDBRecordLink<CCDTierRecord> *defaultTier = new(ELeave) CMDBRecordLink<CCDTierRecord>(KCDTIdGlobalSettingsRecord | KCDTIdDefaultTier); 
+    CleanupStack::PushL(defaultTier);
+    defaultTier->SetRecordId(1);
+    
+    defaultTier->LoadL(iSession.iOwner);
+    
+    if (CommsDat::CommsDatSchema::IsRecord(iElement.ElementId()))
+        {
+        CCDGlobalSettingsRecord& globalSettings = static_cast<CCDGlobalSettingsRecord&>(iElement);
+        
+        if (! globalSettings.iDefaultTier.IsNull())
+            {
+            defaultTier->SetL(globalSettings.iDefaultTier);
+            }
+        }
+
+    TMDBElementId targetId = CommsDatSchema::GetLinkIdL(iSession.iOwner, defaultTier->ElementId(), defaultTier->GetL(), KCDTIdTierRecord/*, NULL*/);
+    
+    CleanupStack::PopAndDestroy(defaultTier);
+
+    SetRecordId(targetId);
+         
+    // Now populate the data from the input element
+    CreateMapL();
+    }
+
+
+void CCDMapperGlobalSettingsRecord::CreateMapL()
+/*
+Populate the values of each each element in the map from data in the input element
+following a unique set of mapping rules.
+NB. Should only use data in the input element (iElement), not the database
+The record ids of the mapping elements have already been set in InitMapL
+      
+@internalComponent
+*/
+    {           
+    //switch (iElement.TypeId())
+    switch (iElement.ElementId() & KCDMaskShowType)
+        {
+       
+        case KCDTIdGlobalSettingsRecord | KCDMaskShowFieldType:
+            {
+            CCDGlobalSettingsRecord* globalSettings = static_cast<CCDGlobalSettingsRecord*>(&iElement);
+            
+            if (Changed(globalSettings->iDefaultSnap))
+            	{
+            	/* There are cases when the 'DefaultSnap' field in the GS record
+            	 * is 0 (explicitly). In this case the GS mapper checks wheather
+            	 * the given field is changed or not (it's changed) BUT during the
+            	 * STORE operation we don't want to store and map the 0 value because
+            	 * this would mean to overwrite the default AP field in the NetworkTier,
+            	 * which is set to a default value form the meshpreface.cfg file.
+            	 * So the check here checks:
+            	 * if we are in a STORE operation and the DefualtSNAP field in the GS
+            	 *    record is 0 then we change the field back to the 'unchanged state'.*/
+            	if (0 == globalSettings->iDefaultSnap.GetL() &&
+            	    EStore == iOperation)
+            		{
+            		//change back the field to the 'unchanged' state
+            		iDefaultAccessPoint.SetElementId(iDefaultAccessPoint.ElementId() & ~KCDChangedFlag);
+            		}
+            	else
+            		{
+            		//Assuming that the defaultSnap id the Snap config file is an AP record id
+            		iDefaultAccessPoint.SetL(KCDTIdAccessPointRecord | (globalSettings->iDefaultSnap << 8));
+            		}
+            	}
+
+            if (Changed(globalSettings->iPromptForSnap))
+                {
+                iPromptUser.SetL(globalSettings->iPromptForSnap);
+                }
+
+            break;
+            }
+        //case KCDTIdDefaultAccessPoint :
+        case KCDTIdDefaultSnap :
+            {
+        	if (Changed(iElement))
+                {
+                iDefaultAccessPoint.SetL(*static_cast<CMDBRecordLinkBase*>(&iElement));
+                }
+            break;
+            }
+        case KCDTIdPromptForSnap :
+            {
+            if (Changed(iElement))
+                {
+                iPromptUser.SetL(*static_cast<CMDBField<TBool>*>(&iElement)); 
+                }
+            break;
+            }
+        default :
+            {
+            ASSERT(KErrNotFound); // hmmm... shouldn't get here.
+            User::Leave(KErrNotFound); 
+            }
+        }
+    }
+
+/**
+    if the mapped fields are already existing in the Tier record on the Network
+    level, they should be deleted.
+*/
+/*virtual*/ void CCDMapperGlobalSettingsRecord::PrepareToStoreL()
+    {
+    //Create the storage for the original GlobalSettings record...
+    iSession.MaybeCreateNodeL(iElement);
+        
+    if (Changed(iPromptUser))
+        {
+        iPromptUser.SetRecordId(RecordId());
+        iPromptUser.DeleteL(iSession.iOwner);
+        }
+        
+    if (Changed(iDefaultAccessPoint))
+        {
+        iDefaultAccessPoint.SetRecordId(RecordId());
+        iDefaultAccessPoint.DeleteL(iSession.iOwner);
+        }
+	
+    }
+
+TBool CCDMapperGlobalSettingsRecord::Mapped(TMDBElementId aElementId)
+/*
+Return ETrue for any element that is mapped.  
+
+@internalComponent
+*/
+    {
+    //switch(aElementId & KCDMaskShowFieldType)
+    switch(aElementId & KCDMaskShowType)
+		{
+ 		case KCDTIdDefaultSnap :
+		case KCDTIdPromptForSnap :
+		    {
+            return ETrue;
+		    }
+        }
+	return EFalse; 
+    }
+	
+TBool CCDMapperGlobalSettingsRecord::NeedsMapping(CMDBElement& aElement)
+/*
+Return ETrue for any element that is mapped.  
+
+@internalComponent
+*/
+    {
+    if(CommsDat::CommsDatSchema::IsRecord(iElement.ElementId()))
+        {
+        //this is a record mapping and the session used is not the latest. So let's have a mapper...
+        /*CCDGlobalSettingsRecord& globalSettings = static_cast<CCDGlobalSettingsRecord&>(iElement);
+   
+        if (Changed(globalSettings.iDefaultSnap) ||
+            Changed(globalSettings.iPromptForSnap)   )
+            {
+            return ETrue;
+            }*/
+        return ETrue;
+        }
+
+    return Mapped(aElement.ElementId());
+    }
+
+
+void CCDMapperGlobalSettingsRecord::MapResultsL()
+/*
+Map results to original element
+
+@internalComponent
+*/
+    {
+    //switch (iElement.TypeId())
+    switch (iElement.ElementId() & KCDMaskShowType)
+        {
+       
+        case KCDTIdGlobalSettingsRecord | KCDMaskShowFieldType:
+            {
+            CCDGlobalSettingsRecord* globalSettings = static_cast<CCDGlobalSettingsRecord*>(&iElement);
+            
+            globalSettings->iDefaultSnap.SetL(iDefaultAccessPoint);
+            //give back just the record number of the linked AP - as in the good old days...
+            CMDBRecordLink<CCDAccessPointRecord>* defaultSnap = static_cast<CMDBRecordLink<CCDAccessPointRecord>*>(&(globalSettings->iDefaultSnap));
+            *defaultSnap = (*defaultSnap & KCDMaskShowRecordId) >> 8;
+            Sync(globalSettings->iDefaultSnap);
+            
+            globalSettings->iPromptForSnap.SetL(iPromptUser);
+            Sync(globalSettings->iPromptForSnap);
+            
+            break;
+            }
+        case KCDTIdDefaultSnap :
+        	
+            {
+            //CMDBField<TInt>* defaultSnap = static_cast<CMDBField<TInt>*>(&iElement);
+            CMDBRecordLink<CCDAccessPointRecord>* defaultSnap = static_cast<CMDBRecordLink<CCDAccessPointRecord>*>(&iElement);
+            defaultSnap->SetL(iDefaultAccessPoint);
+            //give back just the record number of the linked AP - as in the good old days...
+            *defaultSnap = (*defaultSnap & KCDMaskShowRecordId) >> 8;
+            Sync(*defaultSnap);
+            break;
+            }
+        case KCDTIdPromptForSnap :
+            {
+            CMDBField<TBool>* promptUser = static_cast<CMDBField<TBool>*>(&iElement);
+            promptUser->SetL(iPromptUser); 
+            Sync(*promptUser);
+            break;
+            }
+        default :
+            {
+            ASSERT(KErrNotFound); // hmmm... shouldn't get here.
+            User::Leave(KErrNotFound); 
+            }
+        }
+    }
+
+
+/************************* Mapper for IAPSelection Table **************************************
+ * KCDTIdIapPrioritySelectionPolicyRecord   CCDIAPPrioritySelectionPolicyRecord
+ * 
+ * The IAP Selection table is deprecated and completely replaced by the APSelectionTable,
+ *
+ * KCDTIdApPrioritySelectionPolicyRecord  CCDIAPPrioritySelectionPolicyRecord
+ *
+ * As IAPs map directly to APs, the IAP Selection Table that links to IAPs can map directly to 
+ * an AP selecton Table that points to APs that each map to a single IAP
+ * 
+ * The mapping can be very simple because the record id, name, tag and so on can be identical
+ */
+
+#define KCDTIdIapPrioritySelectionPolicyRecordMapper    9880
+START_ATTRIBUTE_TABLE( CCDMapperIAPPrioritySelectionPolicyRecord, KCDTIdIapPrioritySelectionPolicyRecordMapper, KCDTIdIapPrioritySelectionPolicyRecordMapper)
+  	X_REGISTER_ATTRIBUTE( CCDMapperIAPPrioritySelectionPolicyRecord, iAp1,         TMDBLinkNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperIAPPrioritySelectionPolicyRecord, iAp2,         TMDBLinkNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperIAPPrioritySelectionPolicyRecord, iAp3,         TMDBLinkNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperIAPPrioritySelectionPolicyRecord, iAp4,         TMDBLinkNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperIAPPrioritySelectionPolicyRecord, iAp5,         TMDBLinkNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperIAPPrioritySelectionPolicyRecord, iAp6,         TMDBLinkNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperIAPPrioritySelectionPolicyRecord, iAp7,         TMDBLinkNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperIAPPrioritySelectionPolicyRecord, iAp8,         TMDBLinkNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperIAPPrioritySelectionPolicyRecord, iAp9,         TMDBLinkNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperIAPPrioritySelectionPolicyRecord, iAp10,        TMDBLinkNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperIAPPrioritySelectionPolicyRecord, iAp11,        TMDBLinkNum)
+	X_REGISTER_ATTRIBUTE( CCDMapperIAPPrioritySelectionPolicyRecord, iAp12,        TMDBLinkNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperIAPPrioritySelectionPolicyRecord, iAp13,        TMDBLinkNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperIAPPrioritySelectionPolicyRecord, iAp14,        TMDBLinkNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperIAPPrioritySelectionPolicyRecord, iAp15,        TMDBLinkNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperIAPPrioritySelectionPolicyRecord, iApCount,     TMDBNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperIAPPrioritySelectionPolicyRecord, iRecordTag,   TMDBNum)
+	X_REGISTER_ATTRIBUTE( CCDMapperIAPPrioritySelectionPolicyRecord, iRecordName,  TMDBText)
+END_ATTRIBUTE_TABLE()
+
+CCDMapperIAPPrioritySelectionPolicyRecord::CCDMapperIAPPrioritySelectionPolicyRecord(CMDBElement& aElement,CMDBSessionImpl& aSession, const TOperation& aOperation)
+  : CCDMapper(KCDTIdApPrioritySelectionPolicyRecord | (aElement.ElementId() & KCDMaskShowRecordId), aElement, aSession, aOperation),
+    iAp1(KCDTIdAp1),
+    iAp2(KCDTIdAp2),
+    iAp3(KCDTIdAp3),
+    iAp4(KCDTIdAp4),
+    iAp5(KCDTIdAp5),
+    iAp6(KCDTIdAp6),
+    iAp7(KCDTIdAp7),
+    iAp8(KCDTIdAp8),
+    iAp9(KCDTIdAp9),
+    iAp10(KCDTIdAp10),
+    iAp11(KCDTIdAp11),
+    iAp12(KCDTIdAp12),
+    iAp13(KCDTIdAp13),
+    iAp14(KCDTIdAp14),
+    iAp15(KCDTIdAp15),
+    iApCount(KCDTIdApCount),
+    iRecordTag(KCDTIdRecordTag | KCDTIdApPrioritySelectionPolicyRecord),
+    iRecordName(KCDTIdRecordName | KCDTIdApPrioritySelectionPolicyRecord)
+    {
+    //Check whether the original record is set as a 'KCDNewRecordRequest'...
+    if (CommsDatSchema::IsNewRecordRequest(iElement.ElementId()))
+        {
+        SetRecordId(KCDNewRecordRequest);
+        }
+    }
+
+CCDMapperIAPPrioritySelectionPolicyRecord::~CCDMapperIAPPrioritySelectionPolicyRecord()
+	{
+	delete origMappedDataInDB;
+	}
+
+void CCDMapperIAPPrioritySelectionPolicyRecord::ConstructL()
+/*
+Iterate through the mapper element and populate each entry 
+following a unique set of mapping rules.
+The element is populated by information from both the input element and the database
+ConstructL is performed on data input and retrieval.  Mustn't include calls specific to only one or  the other
+@internalComponent
+*/
+    {   
+     switch (iElement.TypeId())
+        {
+        case KCDTIdRecordTag :
+            {
+            if (Changed(iElement))
+                {
+                iRecordTag.SetL(*static_cast<CMDBField<TInt>*>(&iElement));
+                } 
+            break;
+            }
+        case KCDTIdRecordName :
+            {
+            if (Changed(iElement))
+                {
+                iRecordName.SetL(*static_cast<CMDBField<TDesC>*>(&iElement));
+                }
+            break;
+            }
+        case KCDTIdIapCount :
+            {
+            if (Changed(iElement))
+                {
+                iApCount.SetL(*static_cast<CMDBField<TInt>*>(&iElement));
+                }
+            break;
+            }
+        
+        case KCDTIdIapPrioritySelectionPolicyRecord | KCDMaskShowFieldType:
+            {
+  
+            // NB.  This function relies on APs being already present
+
+            //CMDBElement& thisElement = static_cast<CMDBElement&>(*this);
+  
+            CCDIAPPrioritySelectionPolicyRecord& inputElement = static_cast<CCDIAPPrioritySelectionPolicyRecord&>(iElement);
+            
+           if (Changed(inputElement.iRecordTag))
+                {
+                iRecordTag.SetL(inputElement.iRecordTag);
+                }    
+            if (Changed(inputElement.iRecordName))
+                {
+                iRecordName.SetL(inputElement.iRecordName);
+                }
+            if (Changed(inputElement.iIapCount))
+                {
+                iApCount.SetL(inputElement.iIapCount);
+                }
+            	
+            // as every other field is the same type and the mapping rule is identical for each 
+            // and mapping is 1:1, just iterate through the fields and map each one
+            TInt fieldCounter(15); // only need to map this many fields
+
+            TMetaVTableIterator mapperAttribIter(this);
+            SVDataTableEntry const* mapperEntry = NULL;
+
+            TMetaVTableIterator inputAttribIter(&iElement);
+            SVDataTableEntry const* inputEntry = NULL;
+             
+            // NB this only works in this case because entries map exactly....
+            while ( (mapperEntry = mapperAttribIter++)  != NULL &&
+                    (inputEntry = inputAttribIter++)    != NULL &&
+                    fieldCounter-- > 0 )
+                {
+	            CMDBField<TUint32>* inputFieldPtr = reinterpret_cast<CMDBField<TUint32>*>(iElement.GetAttribPtr(inputEntry->iOffset));
+	            //CMDBRecordLink<CCDIAPRecord>* inputFieldPtr = reinterpret_cast<CMDBRecordLink<CCDIAPRecord>*>(GetAttribPtr(mapperEntry->iOffset));
+                //if (inputFieldPtr && Changed(*inputFieldPtr) )
+	            //we need to check the changed flag too -> somebody changes a link to 0...
+                if (inputFieldPtr/* && ((*inputFieldPtr != NULL) || Changed(*inputFieldPtr)) */)
+                    {
+                    CMDBRecordLink<CCDAccessPointRecord>* mapperFieldPtr = reinterpret_cast<CMDBRecordLink<CCDAccessPointRecord>*>(GetAttribPtr(mapperEntry->iOffset));
+                    if (mapperFieldPtr)
+                        {
+                        if ( ( (*inputFieldPtr) & KCDMaskShowType ) == 0 &&
+                             ( (*inputFieldPtr) & KLinkableTag ) == 0 )
+                             //there is only a number for the IAP link in the table...
+                            {
+                            if (*inputFieldPtr == 0)
+                            	{
+                            	//special case, the link is 0 
+                            	mapperFieldPtr->SetL(*inputFieldPtr);
+                            	
+                            	if (!Changed(*inputFieldPtr))
+                            		{
+                            		//this means that we have to remove the changed flag from our mapped field
+                            		//because orginally no value was set for the input field that's why it's 0.
+                            		mapperFieldPtr->SetElementId(mapperFieldPtr->ElementId() & ~KCDChangedFlag);
+                            		}
+                            	}
+                            else
+                            	{
+                            	mapperFieldPtr->SetL(*inputFieldPtr | KLinkableTag);
+                            	}
+                            }
+                        else
+                            //the link is correctly set:
+                            //it's in Link.<TableName>.<TagId> OR
+                            //        <TableName>.<RecordId> format.
+                            {
+                            /*IMPORTANT: this code will work ONLY if the linking in the original
+                                         IAPPrioritySelectionPolicyTable is done by record ID.
+                                         
+                                         If the linking is by TagId then a FindL is needed here...*/
+                            if (!Changed(*inputFieldPtr))
+                            	{
+                            	//This means that there is a link field in the IAPPrioritySelPol record where
+                            	//the link field is correctly set but is't not changed. This means that this field
+                            	//is already stored in the DB. So we can try to read the already mapped element.
+                            	mapperFieldPtr->SetRecordId(iElement.RecordId());
+                            	TRAPD(err, mapperFieldPtr->LoadL(iSession.iOwner));
+                            	if (KErrNone != err)
+                            		{
+                            		//the field is not in the database. Is the client playing with us??
+                            		TUint field = *inputFieldPtr & KCDMaskShowRecordId;
+                            		
+                            		mapperFieldPtr->SetL( (field >> 8) | KLinkableTag);
+                            		}
+                            	}
+                            else
+                            	{
+                            	//this is a modified field
+                            	TUint field = *inputFieldPtr & KCDMaskShowRecordId;
+                            	
+                            	mapperFieldPtr->SetL( (field >> 8) | KLinkableTag);
+                            	}
+                            }
+                        }
+                    }
+                }
+            break;
+            }
+        default:
+        	{
+        	//find out which field is used in the IAPPriorityselPol record
+        	CCDIAPPrioritySelectionPolicyRecord* iapPriorSelPol = static_cast<CCDIAPPrioritySelectionPolicyRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdIapPrioritySelectionPolicyRecord));
+        	CleanupStack::PushL(iapPriorSelPol);
+        	
+            TInt fieldCounter(15); // only need to map this many fields
+
+            TMetaVTableIterator mapperAttribIter(this);
+            SVDataTableEntry const* mapperEntry = NULL;
+
+            TMetaVTableIterator inputAttribIter(iapPriorSelPol);
+            SVDataTableEntry const* inputEntry = NULL;
+            
+            CMDBField<TUint32>* origInputFieldPtr = static_cast<CMDBField<TUint32>*>(&iElement);
+            
+            // NB this only works in this case because entries map exactly....
+            while ( (mapperEntry = mapperAttribIter++)  != NULL &&
+                    (inputEntry = inputAttribIter++)    != NULL &&
+                    fieldCounter-- > 0 )
+            	{
+            	CMDBField<TUint32>* inputFieldPtr = reinterpret_cast<CMDBField<TUint32>*>(iapPriorSelPol->GetAttribPtr(inputEntry->iOffset));
+            	
+            	TMDBElementId filteredOrigInputElemId = origInputFieldPtr->ElementId() & KCDMaskShowType; 
+            	
+            	if ( inputFieldPtr &&
+            		 inputFieldPtr->ElementId() == filteredOrigInputElemId  )
+            		{
+            		CMDBRecordLink<CCDAccessPointRecord>* mapperFieldPtr = reinterpret_cast<CMDBRecordLink<CCDAccessPointRecord>*>(GetAttribPtr(mapperEntry->iOffset));
+            		if (mapperFieldPtr)
+            			{
+                        if ( ( (*origInputFieldPtr) & KCDMaskShowType ) == 0 &&
+                             ( (*origInputFieldPtr) & KLinkableTag ) == 0 )
+                             //there is only a number for the IAP link in the table...
+                            {
+                            if (*origInputFieldPtr == 0)
+                            	{
+                            	//special case, the link is 0 
+                            	mapperFieldPtr->SetL(*origInputFieldPtr);
+                            	
+                            	if (!Changed(*origInputFieldPtr))
+                            		{
+                            		//this means that we have to remove the changed flag from our mapped field
+                            		//because orginally no value was set for the input field that's why it's 0.
+                            		mapperFieldPtr->SetElementId(mapperFieldPtr->ElementId() & ~KCDChangedFlag);
+                            		}
+                            	}
+                            else
+                            	{
+                            	mapperFieldPtr->SetL(*origInputFieldPtr | KLinkableTag);
+                            	}
+                            }
+                        else
+                            //the link is correctly set:
+                            //it's in Link.<TableName>.<TagId> OR
+                            //        <TableName>.<RecordId> format.
+                            {
+                            /*IMPORTANT: this code will work ONLY if the linking in the original
+                                         IAPPrioritySelectionPolicyTable is done by record ID.
+                                         
+                                         If the linking is by TagId then a FindL is needed here...*/
+                            if (!Changed(*origInputFieldPtr))
+                            	{
+                            	//This means that there is a link field in the IAPPrioritySelPol record where
+                            	//the link field is correctly set but is't not changed. This means that this field
+                            	//is already stored in the DB. So we can try to read the already mapped element.
+                            	mapperFieldPtr->SetRecordId(iElement.RecordId());
+                            	TRAPD(err, mapperFieldPtr->LoadL(iSession.iOwner));
+                            	if (KErrNone != err)
+                            		{
+                            		//the field is not in the database. Is the client playing with us??
+                            		TUint field = *origInputFieldPtr & KCDMaskShowRecordId;
+                            		
+                            		mapperFieldPtr->SetL( (field >> 8) | KLinkableTag);
+                            		}
+                            	}
+                            else
+                            	{
+                            	//this is a modified field
+                            	TUint field = *origInputFieldPtr & KCDMaskShowRecordId;
+                            	if (field)
+                            		{
+                            		mapperFieldPtr->SetL( (field >> 8) | KLinkableTag);
+                            		}
+                            	else
+                            		{
+                            		mapperFieldPtr->SetL(0);
+                            		}
+                            	}
+                            }
+            			}
+            		}
+            	}
+            CleanupStack::PopAndDestroy(iapPriorSelPol);
+            break;
+        	}
+        }
+    }
+
+void CCDMapperIAPPrioritySelectionPolicyRecord::PreMappingsL()
+	{
+	if ( KCDTIdRecordTag != iElement.TypeId() &&
+	     KCDTIdRecordName != iElement.TypeId() &&
+	     KCDTIdIapCount != iElement.TypeId() )
+		{
+		if (EFind == iOperation)
+			{
+			//we don't know the elementId of the orig container so we can't call LoadL
+	    	//from the input value we can find the link level AP. Following the link
+	    	//backwards we can find the IPProto level AP.
+	    	//1. find the already changed element in the mapper object
+	    	CMDBRecordLink<CCDAccessPointRecord>* apXLink = &(this->iAp1);
+	    	for (TInt i = 1; i<= MaxLinkCount; ++i)
+	    		{
+	    		if (Changed(*apXLink))
+	    			{
+	    			//this is the changed element
+	    			*apXLink = CommsDatSchema::GetLinkIdL(iSession.iOwner, apXLink->ElementId(), *apXLink, 0);
+	    			
+	    			//at this point we know that what is the link level AP which is the pair of the IAP given as
+	    			//a value in the IAPPrioritySelPol link. Let's find the IPProto level AP which this link level
+	    			//AP is linking from.
+	    			CMDBField<TInt>* linkLevelAPTagId = new(ELeave) CMDBField<TInt>(*apXLink | KCDTIdRecordTag);
+	    			CleanupStack::PushL(linkLevelAPTagId);
+	    			
+	    			linkLevelAPTagId->SetRecordId((*apXLink & KCDMaskShowRecordId) >> 8);
+	    			linkLevelAPTagId->LoadL(iSession.iOwner);
+	    			
+	    			CMDBRecordSet<CCDAccessPointRecord>* apRecordSet = new(ELeave) CMDBRecordSet<CCDAccessPointRecord>(KCDTIdAccessPointRecord);
+	    			CleanupStack::PushL(apRecordSet);
+	    			
+	    			CCDAccessPointRecord* apRecord = static_cast<CCDAccessPointRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdAccessPointRecord));
+	    			CleanupStack::PushL(apRecord);
+	    			
+	    			apRecord->iCustomSelectionPolicy.SetL(*linkLevelAPTagId);
+	
+	    			/* Find all of the AccessPoint records records in the database which have the given 
+	    			 * customSelectionPolicy value. It's VERY VERY VERY expensive. However this is the only way we can
+	    			 * search back the links from the link level up to the APPrioritySelPol record.
+	    			 */
+	    			apRecordSet->iRecords.AppendL(apRecord);
+	    			
+	    			//the ownership is at the recordset already
+	    			//CleanupStack::PopAndDestroy(apRecord);
+	    			CleanupStack::Pop(apRecord);
+	    			
+	    			TInt recCount = 0;
+	    			if(apRecordSet->FindL(iSession.iOwner))
+	    				{
+	    				recCount = apRecordSet->iRecords.Count();
+	    				}
+	    			if (recCount > 0)
+	    				{
+	    				//we have records with the given customSelectionPolicy value
+	    				//now have to find that which accesspoint elementID ws set in the given position of the mapper object
+	    				//originally.
+	    				
+	    				CCDAPPrioritySelectionPolicyRecord* probeApPrioritySelPol = static_cast<CCDAPPrioritySelectionPolicyRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdApPrioritySelectionPolicyRecord));
+	    				CleanupStack::PushL(probeApPrioritySelPol);
+	    				
+	    				//we know that which field was modified originally
+	    				CMDBRecordLink<CCDAccessPointRecord>* probeField = &(probeApPrioritySelPol->iAp1);
+	    				
+	    				//position the field correctly
+	    				for (TInt j = 1; j < i; ++j)
+	    					{
+	    					++probeField;
+	    					}
+	    				
+	    				TBool found = EFalse;
+	    				for (TInt j = 0; (j < apRecordSet->iRecords.Count()) && !found; ++j)
+	    					{
+	    					probeField->SetL(apRecordSet->iRecords[j]->ElementId());
+	    					if (probeApPrioritySelPol->FindL(iSession.iOwner))
+	    						{
+	    						found = ETrue;
+	    						}
+	    					}
+	    				
+	    				if (found)
+	    					{
+	    					//ok, got the correct record
+	    					apXLink->SetL(*probeField);
+	    					}
+	    				else
+	    					{
+	    					// no apprioritySelPol record found with the given accesspoint link
+	    					//User::Leave(KErrNotFound);
+	    					return;
+	    					}
+	    				
+	    				CleanupStack::PopAndDestroy(probeApPrioritySelPol);
+	    				}
+	    			else
+	    				{
+	    				//no records were found with the given customSelectionPolicy value
+	    				//User::Leave(KErrNotFound);
+	    				return;
+	    				}
+	    			
+	    			CleanupStack::PopAndDestroy(apRecordSet);
+	    			CleanupStack::PopAndDestroy(linkLevelAPTagId);
+	    			}
+	    		++apXLink;
+	    		}
+			}
+		else
+			{
+			//load the original mapped element.
+			origMappedDataInDB = static_cast<CCDAPPrioritySelectionPolicyRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdApPrioritySelectionPolicyRecord));
+			origMappedDataInDB->SetRecordId(iElement.RecordId());
+			
+			origMappedDataInDB->LoadL(iSession.iOwner);
+			
+			CCDAPPrioritySelectionPolicyRecord* origMappedRecord = static_cast<CCDAPPrioritySelectionPolicyRecord*>(origMappedDataInDB);
+			if ( KCDMaskShowFieldType != (iElement.ElementId() & KCDMaskShowFieldType) )
+				{
+				//this is a field. What happens here is we fill up the mapper with the mapped object 
+				//already stored in the db except that field which is currently changed and already set in the
+				//ConstructL of the mapper.
+				CMDBRecordLink<CCDAccessPointRecord>* origMappedFieldPtr = &(origMappedRecord->iAp1);
+				CMDBRecordLink<CCDAccessPointRecord>* currentMappedFieldPtr = &(this->iAp1);
+				
+				for (TInt i = 1; i <= MaxLinkCount; ++i)
+					{
+					if (!Changed(*currentMappedFieldPtr) && currentMappedFieldPtr->IsNull())
+						{
+						//it's not the field which has been changed so fill up from the DB
+						currentMappedFieldPtr->SetL(*origMappedFieldPtr);
+						currentMappedFieldPtr->SetElementId(currentMappedFieldPtr->ElementId() & ~ KCDChangedFlag);
+						//it's possible that the field value is 0 -> so remove the not_null flag in this case
+						if (0 == *currentMappedFieldPtr)
+							{
+							currentMappedFieldPtr->SetElementId(currentMappedFieldPtr->ElementId() & ~ KCDNotNullFlag);
+							}
+						}
+					else
+						{
+						//there is a changed element
+						if (EDelete == iOperation)
+							{
+							//this is a tricky case here. There is a DeleteL call on a field in some IAPPrioritySelPol
+							//record. Since the mapping is record based we cannot delete the whole record (I mean the
+							//mapped APPrioritySelPol record) so we have to change the elementId of the mapper object
+							//because wwithout this the MaybeDeleteNodeL call would delete the whole record and this is
+							//not we would like to do here...
+							SetElementId(ElementId() & ~KCDMaskShowFieldType);
+							SetElementId(ElementId() | (currentMappedFieldPtr->ElementId() & KCDMaskShowFieldType));
+							currentMappedFieldPtr->SetElementId(currentMappedFieldPtr->ElementId() | KCDChangedFlag);
+							}
+						}
+					++origMappedFieldPtr;
+					++currentMappedFieldPtr;
+					}
+				//ok all of the fields are now ready to handle. Set the count field too
+				this->iApCount.SetL(origMappedRecord->iApCount);
+				}
+			}
+		}
+	}
+
+
+TBool CCDMapperIAPPrioritySelectionPolicyRecord::NeedsMapping(CMDBElement& /*aElement*/)
+    {
+    return ETrue;
+    }
+
+/*virtual*/ void CCDMapperIAPPrioritySelectionPolicyRecord::PrepareToStoreL()
+    {
+    CMDBElement& thisElement = static_cast<CMDBElement&>(*this);
+    
+    iSession.MaybeCreateNodeL(thisElement);
+    if (iElement.ElementId() & KCDNewRecordRequest == KCDNewRecordRequest)
+        {
+        iElement.SetRecordId(this->RecordId());
+        }
+    }
+
+TBool CCDMapperIAPPrioritySelectionPolicyRecord::Mapped(TMDBElementId /*aElementId*/)
+/*
+Return ETrue for any element that is mapped.  
+
+@internalComponent
+*/
+    {
+    // Every element is mapped in this record so return true
+    return ETrue;
+    }
+	
+
+void CCDMapperIAPPrioritySelectionPolicyRecord::MapResultsL()
+/*
+Map results to original element
+
+@internalComponent
+*/
+    {
+    switch (iElement.TypeId())
+        {
+        case KCDTIdRecordTag :
+            {
+            CMDBField<TUint32>& recordTag = static_cast<CMDBField<TUint32>&>(iElement);
+            recordTag.SetL(iRecordTag);
+            Sync(recordTag);
+            break;
+            }
+        case KCDTIdRecordName :
+            {
+            CMDBField<TDesC>& recordName = static_cast<CMDBField<TDesC>&>(iElement);
+            recordName.SetL(iRecordName);
+            Sync(recordName);
+            break;
+            }
+        case KCDTIdIapCount :
+            {
+            CMDBField<TUint32>& iapCount = static_cast<CMDBField<TUint32>&>(iElement);
+            iapCount.SetL(iApCount);
+            Sync(iapCount);
+            break;
+            }
+        
+        case KCDTIdIapPrioritySelectionPolicyRecord | KCDMaskShowFieldType:
+            {
+            CCDIAPPrioritySelectionPolicyRecord& inputElement = static_cast<CCDIAPPrioritySelectionPolicyRecord&>(iElement);
+
+            inputElement.iRecordTag.SetL(iRecordTag);
+            Sync(inputElement.iRecordTag);
+ 
+            inputElement.iRecordName.SetL(iRecordName);
+            Sync(inputElement.iRecordName);
+                
+            inputElement.iIapCount.SetL(iApCount);
+            Sync(inputElement.iIapCount);
+            
+            //NO BREAK HERE - FALL THROUGH TO DEFAULT
+            }
+        default :
+            {
+            if ( KCDMaskShowFieldType != (iElement.ElementId() & KCDMaskShowFieldType ) )
+            //Field mapping
+                {
+                const STableLookup* tableInfoPtr = CommsDatSchemaV1_1::iTableLookup;
+                TMDBElementId origTableId = iElement.ElementId() & KCDMaskShowRecordType;
+                TInt i = 0;
+                
+                while( tableInfoPtr && tableInfoPtr->iTableId != 0 && (tableInfoPtr->iTableId) != origTableId)
+                    {
+                    ++i;        
+                    ++tableInfoPtr;
+                    }
+                    
+                //At this point we know that what is the table of the mapped field.
+                //Now we should search for the field in the table and get the position of it.
+                //it is important because as the mapping here is 1:1 this position will be the 
+                //position of the mapped field either.
+                const CommsDat::SRecordTypeInfo* fieldInfoPtr = CommsDatSchemaV1_1::iTableLookup[i].iFields;
+                TMDBElementId cleanOrigFieldId = iElement.ElementId() & KCDMaskShowType;
+                TInt fieldPosition = 0;
+                
+                //Skip the tagId and the name fields...
+                ++fieldInfoPtr;
+                ++fieldInfoPtr;
+                
+                while( fieldInfoPtr && fieldInfoPtr->iTypeId != 0 && (fieldInfoPtr->iTypeId) != cleanOrigFieldId)
+                {
+                ++fieldPosition;        
+                ++fieldInfoPtr;
+                }
+                
+                TMetaVTableIterator mapperAttribIter(this);
+                SVDataTableEntry const* mapperEntry = NULL;
+                CMDBField<TUint32>* mapperFieldPtr = NULL;
+                
+                //just get into the right position with the attribute iterator for the mapper
+                while ( (mapperEntry = mapperAttribIter++) != NULL && 
+                        fieldPosition-- >= 0 )
+                    {
+                    mapperFieldPtr = reinterpret_cast<CMDBField<TUint32>*>(GetAttribPtr(mapperEntry->iOffset));
+                    }
+                
+	                CMDBField<TUint32>* custSelPolOfTheMappedRecord = new(ELeave) CMDBField<TUint32>((*mapperFieldPtr) | KCDTIdCustomSelectionPolicy);
+	                CleanupStack::PushL(custSelPolOfTheMappedRecord);
+	                custSelPolOfTheMappedRecord->LoadL(iSession.iOwner);
+	                
+	                TInt mappedIAPRecId = (*custSelPolOfTheMappedRecord) << 8;
+	                
+	                CleanupStack::PopAndDestroy(custSelPolOfTheMappedRecord);
+	                
+                    CMDBField<TUint32>& mappedField = reinterpret_cast<CMDBField<TUint32>& >(iElement);
+                    mappedField.SetL(KCDTIdIAPRecord | mappedIAPRecId);
+                    Sync(mappedField);
+                }
+            else
+            //Record mapping
+                {
+                // as every other field is the same type and the mapping rule is identical for each 
+                // and mapping is 1:1, just iterate through the fields and map each one
+                TMetaVTableIterator inputAttribIter(&iElement);
+                SVDataTableEntry const* inputEntry = NULL;
+
+                TMetaVTableIterator mapperAttribIter(this);
+                SVDataTableEntry const* mapperEntry = NULL;
+              
+                TInt fieldCounter(15); // only need to map this many fields (from start of record)
+
+                while ( (mapperEntry = mapperAttribIter++) != NULL && 
+                        (inputEntry = inputAttribIter++) != NULL &&
+                        fieldCounter-- > 0 )
+                    {
+    	            CMDBField<TUint32>* mapperFieldPtr = reinterpret_cast<CMDBField<TUint32>*>(GetAttribPtr(mapperEntry->iOffset));
+                    if( mapperFieldPtr )
+                    /*At this point we already know that what is recordNumber of the MAPPED element.
+                      So all we have to do is to load the mapped element and read its TagId.*/
+                        {                        
+                        if ((mapperFieldPtr->ElementId() & KCDNotNullFlag) != 0)
+                            {
+                            if (0 != *mapperFieldPtr)
+                            	{
+                            	//it's possible that the link value is 0 because there can be holes
+                            	//in the record links...
+	                            CommsDatMapperAndValidator::TAPTypes apType = CheckLinkLevelAPL(*mapperFieldPtr);
+	                            TInt mappedIAPRecId = 0;
+	                            
+	                            if (CommsDatMapperAndValidator::ELinkLevel == apType)
+	                            //this is already a link level AP so the tagId of it can be used as record ID
+	                            //for the pointed IAP record
+	                                {
+	                                CMDBField<TUint32>* tagFieldOfTheMappedRecord = new(ELeave) CMDBField<TUint32>((*mapperFieldPtr) | KCDTIdRecordTag);
+	                                CleanupStack::PushL(tagFieldOfTheMappedRecord);
+	                                tagFieldOfTheMappedRecord->LoadL(iSession.iOwner);
+	                                
+	                                mappedIAPRecId = (*tagFieldOfTheMappedRecord) << 8;
+	                                
+	                                CleanupStack::PopAndDestroy(tagFieldOfTheMappedRecord);
+	                                }
+	                            else
+	                            //the other case is that this is an IPProto level AP (it cannot be network level
+	                            //because it is checked when storing the mapped APPrioritySelPol record).
+	                            //here we have to read the customSelectionPolicy field of the AP which gives us
+	                            //the TagId of the link level AP which the tag id of it is the same as the 
+	                            //recordId of the mapped IAP recordId. :)
+	                                {
+	                                CMDBField<TUint32>* custSelPolOfTheMappedRecord = new(ELeave) CMDBField<TUint32>((*mapperFieldPtr) | KCDTIdCustomSelectionPolicy);
+	                                CleanupStack::PushL(custSelPolOfTheMappedRecord);
+	                                custSelPolOfTheMappedRecord->LoadL(iSession.iOwner);
+	                                
+	                                mappedIAPRecId = (*custSelPolOfTheMappedRecord) << 8;
+	                                
+	                                CleanupStack::PopAndDestroy(custSelPolOfTheMappedRecord);
+	                                }
+	                            
+	                            CMDBField<TUint32>* inputFieldPtr = reinterpret_cast<CMDBField<TUint32>*>(iElement.GetAttribPtr(inputEntry->iOffset));
+	                            if (inputFieldPtr)
+	                                {
+	                                inputFieldPtr->SetL(KCDTIdIAPRecord | mappedIAPRecId);
+	                                Sync(*inputFieldPtr);
+	                                }
+                            	}
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+//this method compared the current mapped APPrioritySelPol record with the one in the database which is the default
+TBool CCDMapperIAPPrioritySelectionPolicyRecord::IsItTheDefaultAPPrioritySelPolRec(/*CCDAPPrioritySelectionPolicyRecord* aDefAPPrioritySelPolRec*/)
+    {
+    TInt defSelPolLinkValue = CommsDatMapperAndValidator::GetDefAPPrioritySelPolLinkValueL(iSession.iOwner);
+    
+    TInt myId = ElementId() & ~KCDMaskShowFieldType;
+    
+    if (defSelPolLinkValue == myId)
+        {
+        return ETrue;
+        }
+    return EFalse;
+    }
+
+/*virtual*/ void CCDMapperIAPPrioritySelectionPolicyRecord::PostMappingsL()
+    {        
+	if ( KCDTIdRecordTag != iElement.TypeId() &&
+	     KCDTIdRecordName != iElement.TypeId() &&
+	     KCDTIdIapCount != iElement.TypeId() )
+		{
+	    TBool def = IsItTheDefaultAPPrioritySelPolRec();
+	    CMDBRecordLink<CCDAccessPointRecord>* apXField = &iAp1;
+	
+	    CCDAPPrioritySelectionPolicyRecord* origMappedRecord = NULL;
+	    CMDBRecordLink<CCDAccessPointRecord>* origApXField = NULL;
+	        
+	    if (origMappedDataInDB)
+	    	{
+	    	origMappedRecord = static_cast<CCDAPPrioritySelectionPolicyRecord*>(origMappedDataInDB);
+	    	origApXField = &(origMappedRecord->iAp1);
+	    	}
+	    
+	    TInt lastValidAPLinkNum = 0;
+	    /*
+	     * We have to go through the list because it's possible that the client modified an IAP link in
+	     * the IAPPriorirytSelPol record and didn't update the IAPCount field. This loop here goes through the
+	     * AP links in the mapped APPrioritySelPol table and counts the valid links and updates the APCount field.
+	     * It's important since it's used during the selection.
+	     * we have to go through all of the links because it's possible that there are 'holes' in the links.
+	     * iap1 = valid link
+	     * iap2 = 0
+	     * iap3 = valid link
+	     * In this special case the apCount will be 3 meaning that there are valid links in the first 3 slots.
+	     */
+	    for (TInt i = 1; /*(*apXField != NULL) &&*/ (i<=MaxLinkCount); ++i)
+	        {        
+	        if ( (EDelete != iOperation) &&
+	        	 (0 != *apXField) )
+	        	{
+		        CommsDatMapperAndValidator::TAPTypes apType;
+		        apType = CheckLinkLevelAPL(*apXField);
+		        
+		        if (CommsDatMapperAndValidator::ELinkLevel == apType)
+		        //The IPProto AP has to be generated...
+		            {
+		            GenerateIPProtoAPL(apXField, i, def);
+		            }
+		        else if (CommsDatMapperAndValidator::EIPProtoLevel == apType)
+		        //this link already points to an IPProto level AP check whether it has the correct linking 
+		        //to the link level AP
+		            {
+		            CheckIPProtoAPL(apXField, i, def);
+		            }
+		        else
+		        //hm... Something is really bad here. Leaving...
+		            {
+		            User::Leave(KErrNotFound);
+		            }
+		        
+		        lastValidAPLinkNum = i;
+	        	
+	        	}
+	        else
+	        	{
+	        	if (KCDMaskShowFieldType == (ElementId() & KCDMaskShowFieldType))
+	        		{
+		        	//the given field is NULL. Is this NULL a result of a modification or was it originally NULL? If it's 
+		        	//NULL because of a modification (user set the field to 0) this means that we have to delete the IPProto
+		        	//level AP linked from the mapped APPrioritySelPol record.
+	        		
+	                /* There is a little trick here. If there are 2 APPrioritySelPol records in the DB where
+	                 * 1 link in each record is linking against the same IPProto AP then the situation 
+	                 * can be the following:
+	                 * APPrioritySelPolRec_1:
+	                 * 		AP1 = IPProto_link_record1
+	                 * 
+	                 * APPrioritySelPolRec_2:
+	                 * 		AP1 = IPProto_link_record1
+	                 * 
+	                 * One APPrioritySelPol record can be already deleted (by the MaybeDeleteNodeL call which was made
+	                 * previously to this postmappings call).
+	                 * So when the program logic tries to find that how many reference does a given
+	                 * IPProto AP have (IPProto_link_record1 in the example above) then it finds that it's only 1 because the
+	                 * other record from which it was linked the 2nd time is already deleted. That's why
+	                 * we give for the search algorithm the original (already deleted) APPrioritySelPol record.
+	                 */ 
+	        		
+		        	if (origApXField && (*origApXField) && origMappedRecord )
+		        		{
+		        		//originally this was not NULL. So we have to delete the linked IPProto level AP.
+		        		//do a deep copy from the original APPrioritySelPol record
+		        		CCDAPPrioritySelectionPolicyRecord* origSelPolRecCopy = static_cast<CCDAPPrioritySelectionPolicyRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdApPrioritySelectionPolicyRecord));
+		        		CleanupStack::PushL(origSelPolRecCopy);
+		        		
+		                TMetaVTableIterator inputAttribIter(origMappedRecord);
+		                SVDataTableEntry const* inputEntry = NULL;
+		                
+		                TMetaVTableIterator copiedAttribIter(origSelPolRecCopy);
+		                SVDataTableEntry const* copiedEntry = NULL;
+		                
+		                TInt fieldCounter = CCDAPPrioritySelectionPolicyRecord::EMaxNrOfAps;
+		                
+		                while ( (inputEntry = inputAttribIter++)    != NULL &&
+		                		(copiedEntry = copiedAttribIter++)    != NULL &&
+		                        fieldCounter-- > 0 )
+		                    {
+		                    //loop for the fields
+		                    CMDBField<TUint32>* inputFieldPtr = reinterpret_cast<CMDBField<TUint32>*>(origMappedRecord->GetAttribPtr(inputEntry->iOffset));
+		                    if ( inputFieldPtr )
+		                        {
+		                        CMDBField<TUint32>* copyFieldPtr = reinterpret_cast<CMDBField<TUint32>*>(origSelPolRecCopy->GetAttribPtr(copiedEntry->iOffset));                        
+		                        copyFieldPtr->SetL(*inputFieldPtr);
+		                        }
+		                    }
+		                
+		                origSelPolRecCopy->iApCount.SetL(origMappedRecord->iApCount);
+		                
+		                //we transfer the ownership of this pointer!!!!!!
+		                
+		                CleanupStack::Pop(origSelPolRecCopy);
+		                
+		        		DeleteIPProtoAPL(origApXField, origSelPolRecCopy);
+		        		
+		        		lastValidAPLinkNum = ForcedCountAPLinks();
+		        		}
+	        		}
+	        	else
+	        		{
+	        		//deleting a field
+	        		//in the PreMappings function the elementId of the field to be deleted was changed by turning on the
+	        		//changed flag on it. In this step we can exemine this flag. If found the corresponding IPProto level
+	        		//AP should be deleted.
+	        		if (Changed(*apXField))
+	        			{
+	        			DeleteIPProtoAPL(origApXField);
+	        			
+	        			lastValidAPLinkNum = ForcedCountAPLinks();
+	        			}
+	        		}
+		        }
+		        ++apXField;
+		        
+		        if (origMappedRecord)
+		        	{
+		        	++origApXField;
+		        	}
+	        }
+	    
+	    TBool countChanged = EFalse;
+	    
+	    if  (iElement.TypeId() == (KCDTIdIapPrioritySelectionPolicyRecord | KCDMaskShowFieldType))
+	        {
+	        CCDIAPPrioritySelectionPolicyRecord& inputElement = static_cast<CCDIAPPrioritySelectionPolicyRecord&>(iElement);
+	        if (KCDChangedFlag == ((inputElement.iIapCount).ElementId() & KCDChangedFlag))
+	        	{
+	        	//the client has changed the iap count field, don't overwrite it
+	        	countChanged = ETrue;
+	        	}
+	        }
+	    
+    	if ( ( ( KCDMaskShowFieldType == (ElementId() & KCDMaskShowFieldType) &&
+    		     EDelete != iOperation ) || 
+    		   ( 0 != (ElementId() & KCDMaskShowFieldType) ) ) &&
+    		static_cast<TInt>(iApCount) != lastValidAPLinkNum &&
+    		!countChanged )
+    		{
+    		//   ( if it's not a record delete _OR_ 
+    		//     it's a simple field operation)  _AND_
+    		//   the original link number is not the same as we counted _AND_
+    		//   the user isn't modifying explicitly the link number
+    		//then we update the record count field
+	        iApCount.SetL(lastValidAPLinkNum);
+	        this->ModifyL(iSession.iOwner);
+    		}
+	    
+/*	    if (EDelete != aOperation &&
+	    	!countChanged &&
+	    	static_cast<TInt>(iApCount) != lastValidAPLinkNum)
+	    	{
+	    	//modify the APCount field. It's important since it's used during the selection process in ESock.
+	        iApCount.SetL(lastValidAPLinkNum);
+	        this->ModifyL(iSession.iOwner);
+	    	}*/
+	    
+	    /* final check: 
+	     * if the default IAPPrioritySelPol (mapped APPrioritySelPol) OR
+	     * the 1st link form the default  IAPPrioritySelPol (mapped APPrioritySelPol)
+	     * was deleted then the default IPProto AP (from the meshpreface file)
+	     * should be linked from the APPrioritySelPol and the IPProto tier records.
+	     */
+	    if ( (EDelete == iOperation ||
+	    	  0 == iApCount ) &&
+	    	 def &&
+	    	 ( KCDMaskShowFieldType == (ElementId() & KCDMaskShowFieldType) ||
+	    	   KCDTIdAp1 == (ElementId() & KCDMaskShowType) ) )
+	    	{
+	    	//generate/link the def IPProto AP
+	    	//1. Is DefIPProto AP in the database
+	    	
+	    	CCDAccessPointRecord* defIpprotoAP = NULL;
+	    	
+	    	if (CommsDatMapperAndValidator::IsDefIPProtoAPInDB(iSession.iOwner))
+	    		{
+	    		//yes, there is -> use it
+	    		defIpprotoAP = CommsDatMapperAndValidator::GetTheDefIPProtoAP(iSession.iOwner);
+	    		CleanupStack::PushL(defIpprotoAP);
+	    		}
+	    	else
+	    		{
+	    		//no there isn't -> generate one
+	    		defIpprotoAP = CommsDatMapperAndValidator::GenerateIPProtoAPL(IPProtoBaseTagId, 
+					                                                          CCDAccessPointRecord::KNoPolicy,
+	    		                                                              iSession.iOwner);
+	    		CleanupStack::PushL(defIpprotoAP);
+	    		
+	    		defIpprotoAP->StoreL(iSession.iOwner);
+	    		}
+	    	
+	    	TPtrC recName(defIpprotoAP->iRecordName);
+	    	if (0 != recName.Compare(KDefaultIPProtoRecName))
+	    		{
+	    		//the name of the selected default IPProto AP is not 'IPProtoDefault'.
+	    		defIpprotoAP->iRecordName.SetMaxLengthL(KDefaultIPProtoRecName().Length());
+	    		defIpprotoAP->iRecordName.SetL(KDefaultIPProtoRecName);
+	    		
+	    		defIpprotoAP->ModifyL(iSession.iOwner);
+	    		}
+	    	
+	    	//2. correct the link in the ipproto Tier record to point to the default IPProto AP
+	    	TInt ipproroTierRecId = CommsDatMapperAndValidator::GetIPProtoTierRecordIdL(iSession.iOwner);
+	    	
+	    	//CMDBRecordLink<CCDAccessPointRecord>* defTierAP = new(ELeave)CMDBRecordLink<CCDAccessPointRecord>(KCDTIdDefaultAccessPoint);
+	    	CMDBField<TInt>* defTierAP = new(ELeave)CMDBField<TInt>(KCDTIdDefaultAccessPoint);
+	    	CleanupStack::PushL(defTierAP);
+	    	
+	    	defTierAP->SetRecordId(ipproroTierRecId);
+	    	defTierAP->LoadL(iSession.iOwner);
+	    	
+		    TMDBElementId elemId = defIpprotoAP->ElementId();
+		    elemId &= KCDMaskHideAttrAndRes;
+		    TMDBElementId tableAndRecordBitMask = KCDMaskShowRecordType | KCDMaskShowRecordId;
+		    elemId &= tableAndRecordBitMask;
+	    	
+		    *defTierAP = elemId;
+		    
+		    defTierAP->ModifyL(iSession.iOwner);
+		    
+	    	CleanupStack::PopAndDestroy(defTierAP);
+	    	CleanupStack::PopAndDestroy(defIpprotoAP);
+	    	
+	    	}
+		}
+    }
+
+TInt CCDMapperIAPPrioritySelectionPolicyRecord::ForcedCountAPLinks()
+	{
+	TInt linkNum = 15;
+	
+	/* Walk backwards on the AP links and return the first valid AP link.
+	 * This is the APCount number.
+	 */
+	CMDBRecordLink<CCDAccessPointRecord>* currAPLink = &(this->iAp15);
+	
+	for (; linkNum > 0; --linkNum)
+		{
+		if ( currAPLink &&
+			 *currAPLink )
+			{
+			break;
+			}
+		--currAPLink;
+		}
+	
+	return linkNum;
+	}
+
+void CCDMapperIAPPrioritySelectionPolicyRecord::CheckIPProtoAPL(CMDBRecordLink<CCDAccessPointRecord>*& aAPPriorityField,
+                                                                TInt aLinkNumber,
+                                                                TBool aIsDefaultAP)
+    {
+    TInt linkAPTagId = 0;
+    
+    if ( KCDMaskShowFieldType == (iElement.ElementId() & KCDMaskShowFieldType) )
+    	{
+	    //it's a record mapping
+	    CCDIAPPrioritySelectionPolicyRecord* ptrIAPPrioritySelPol = static_cast<CCDIAPPrioritySelectionPolicyRecord*>(&iElement);
+	    linkAPTagId = GetTheLinkAPTagIdL(ptrIAPPrioritySelPol, aLinkNumber);
+    	}
+    else
+    	{
+    	//it's field mapping
+    	if (Changed(*aAPPriorityField))
+    		{
+    		CMDBRecordLink<CCDIAPRecord>* ptrIAPPrioritySelPol = static_cast<CMDBRecordLink<CCDIAPRecord>*>(&iElement);
+    		linkAPTagId = GetTheLinkAPTagIdL(ptrIAPPrioritySelPol);
+    		}
+    	else
+    		{
+    		return;
+    		}
+    	}
+    
+    //got the original elementID of the linked IAP record
+    
+    //read the CustomSelectionPolicy field of the IPProto level AP
+    CMDBField<TInt>* custSelPolField = new(ELeave) CMDBField<TInt>(*aAPPriorityField | KCDTIdCustomSelectionPolicy);
+    CleanupStack::PushL(custSelPolField);
+    
+    custSelPolField->LoadL(iSession.iOwner);
+    
+    if (linkAPTagId != *custSelPolField)
+    //The IPProto AP has a wrong linking to the Link level AP. Modify it...
+        {
+        *custSelPolField = linkAPTagId;
+        
+        custSelPolField->ModifyL(iSession.iOwner);
+        }
+    
+    //if this is the default APPrioritySelPol record and the linkNumber is 1 then 
+    //update the defaultAccessPoint link in the network Tier record
+    if (aIsDefaultAP/* &&
+        1 == aLinkNumber*/)
+        {
+        CommsDatMapperAndValidator::ModifyDefaultTierRecordL((custSelPolField->ElementId() & ~KCDMaskShowFieldType) & ~KCDNotNullFlag, 
+                                                             iSession.iOwner);
+        }
+    
+    CleanupStack::PopAndDestroy(custSelPolField);
+    }
+
+void CCDMapperIAPPrioritySelectionPolicyRecord::GenerateIPProtoAPL(CMDBRecordLink<CCDAccessPointRecord>*& aAPPriorityFieldToModify,
+                                                                   TInt aLinkNumber,
+                                                                   TBool aIsDefaultAP)
+
+    {    
+    TInt linkAPTagId = 0;
+        
+    if ( KCDMaskShowFieldType == (iElement.ElementId() & KCDMaskShowFieldType) )
+    	{
+	    //it's a record mapping
+	    CCDIAPPrioritySelectionPolicyRecord* ptrIAPPrioritySelPol = static_cast<CCDIAPPrioritySelectionPolicyRecord*>(&iElement);
+	    linkAPTagId = GetTheLinkAPTagIdL(ptrIAPPrioritySelPol, aLinkNumber);
+    	}
+    else
+    	{
+    	//it's field mapping
+    	if (Changed(*aAPPriorityFieldToModify))
+    		{
+    		CMDBRecordLink<CCDIAPRecord>* ptrIAPPrioritySelPol = static_cast<CMDBRecordLink<CCDIAPRecord>*>(&iElement);
+    		linkAPTagId = GetTheLinkAPTagIdL(ptrIAPPrioritySelPol);
+    		}
+    	else
+    		{
+    		//the given field is not changed -> don't touch anything...
+    		return;
+    		}
+    	}
+    
+    CCDAccessPointRecord* ipprotoAP = NULL;
+        
+    if (!CommsDatMapperAndValidator::IsIPProtoAPAlreadyExistL(linkAPTagId, iSession.iOwner))
+    	{
+    	//The IPProto AP is not existing yet. Generate one.
+	    ipprotoAP = CommsDatMapperAndValidator::GenerateIPProtoAPL(IPProtoBaseTagId,
+	    														   linkAPTagId,
+	                                                               iSession.iOwner);
+	    
+	    CleanupStack::PushL(ipprotoAP);
+	    
+	    //save the generated AP record
+	    ipprotoAP->StoreL(iSession.iOwner);
+    	}
+    else
+    	{
+    	//The IPProto AP is already exsiting. Use that one.
+    	ipprotoAP = CommsDatMapperAndValidator::LoadTheAPL(linkAPTagId, iSession.iOwner);
+    	
+    	CleanupStack::PushL(ipprotoAP);
+    	}
+    
+    TMDBElementId elemId = ipprotoAP->ElementId();
+    elemId &= KCDMaskHideAttrAndRes;
+    TMDBElementId tableAndRecordBitMask = KCDMaskShowRecordType | KCDMaskShowRecordId;
+    elemId &= tableAndRecordBitMask;
+    
+    //a) update the APPrioritySelPol record to point to the newly creeated AP record
+    *aAPPriorityFieldToModify = elemId;
+    
+    this->ModifyL(iSession.iOwner);
+    
+    //b) if this is the default APPrioritySelPol record and the linkNumber is 1 then 
+    //   update the defaultAccessPoint link in the network Tier record
+    if (aIsDefaultAP/* &&
+        1 == aLinkNumber*/)
+        {
+        CommsDatMapperAndValidator::ModifyDefaultTierRecordL(elemId, iSession.iOwner);
+        }
+    
+    CleanupStack::PopAndDestroy(ipprotoAP);
+    }
+
+void CCDMapperIAPPrioritySelectionPolicyRecord::DeleteIPProtoAPL(CMDBRecordLink<CCDAccessPointRecord>*& aAPPriorityField)
+	{
+	TInt refCount = CommsDatMapperAndValidator::CountReferenceToThisIPProtoAPL(*aAPPriorityField, iSession.iOwner);
+	if (1 == refCount)
+		{
+		//ok, we have only 1 reference to the given IPProto AP -> it can be deleted
+		CCDAccessPointRecord* apRecordToBeDeleted = static_cast<CCDAccessPointRecord*>(CCDRecordBase::RecordFactoryL(*aAPPriorityField));
+		CleanupStack::PushL(apRecordToBeDeleted);
+		
+		apRecordToBeDeleted->DeleteL(iSession.iOwner);
+		
+		CleanupStack::PopAndDestroy(apRecordToBeDeleted);
+		}
+	}
+
+//Note - the ownership of the 'aTheAlreadyDeletedRecord' is transferred here!!!!!!
+void CCDMapperIAPPrioritySelectionPolicyRecord::DeleteIPProtoAPL(CMDBRecordLink<CCDAccessPointRecord>*& aAPPriorityField,
+									 							 CCDAPPrioritySelectionPolicyRecord* aTheAlreadyDeletedRecord)
+	{
+	//Note - the ownership of the 'aTheAlreadyDeletedRecord' is transferred to the CountReferenceToThisIPProtoAPL!!!!!!
+	TInt refCount = CommsDatMapperAndValidator::CountReferenceToThisIPProtoAPL(*aAPPriorityField, aTheAlreadyDeletedRecord, iSession.iOwner);
+	if (1 == refCount)
+		{
+		//ok, we have only 1 reference to the given IPProto AP -> it can be deleted
+		CCDAccessPointRecord* apRecordToBeDeleted = static_cast<CCDAccessPointRecord*>(CCDRecordBase::RecordFactoryL(*aAPPriorityField));
+		CleanupStack::PushL(apRecordToBeDeleted);
+		
+		apRecordToBeDeleted->DeleteL(iSession.iOwner);
+		
+		CleanupStack::PopAndDestroy(apRecordToBeDeleted);
+		}
+	}
+
+TInt CCDMapperIAPPrioritySelectionPolicyRecord::GetTheLinkAPTagIdL(CCDIAPPrioritySelectionPolicyRecord* aOrigIAPPrioritySelPolRec,
+                                                                   TInt aLinkNumber)
+    {
+    //TInt iapCount = aOrigIAPPrioritySelPolRec->iIapCount;
+    CMDBRecordLink<CCDIAPRecord>* iapXField = &aOrigIAPPrioritySelPolRec->iIap1;
+    CMDBField<TInt>* apTagId = NULL;
+    TInt tagId = 0;
+    
+    /*for (TInt i = 1; i!=aLinkNumber && i<=iapCount; ++i)
+        {
+        ++iapXField;
+        }*/
+    
+    for (TInt i = 1; i!=aLinkNumber && i<=MaxLinkCount; ++i)
+    	{
+    	++iapXField;
+    	}
+    
+    //got the original elementID of the linked IAP record
+    
+    
+    //read the tagId of the generated Link level AP (if there is any)...
+    
+    apTagId = new(ELeave) CMDBField<TInt>(KCDTIdAccessPointRecord | KCDTIdRecordTag);
+    CleanupStack::PushL(apTagId);
+    
+    
+    if ( ( (*iapXField) & KCDMaskShowType ) == 0 &&
+         ( (*iapXField) & KLinkableTag ) == 0 )
+    	{
+         //there is only a number for the IAP link in the table...
+    	*apTagId = *iapXField;
+    	}
+    else
+    	{
+    	//the IAP link is correctly set. Let's use the recordId from the value field.
+    	*apTagId = (*iapXField & KCDMaskShowRecordId) >> 8;
+    	}
+    
+    if ( !(apTagId->FindL(iSession.iOwner)) )
+    //the link level AP cannot be found. Leaving...
+        {
+        User::Leave(KErrNotFound);
+        }
+    else
+        {
+        tagId = *apTagId;
+        }
+    
+    CleanupStack::PopAndDestroy(apTagId);
+    
+    return tagId;
+    }
+
+
+TInt CCDMapperIAPPrioritySelectionPolicyRecord::GetTheLinkAPTagIdL(CMDBRecordLink<CCDIAPRecord>* aOrigIAPPrioritySelPolField/*,
+                                                                   TInt aLinkNumber*/)
+    {
+    CMDBField<TInt>* apTagId = NULL;
+    TInt tagId = 0;
+    //read the tagId of the generated Link level AP (if there is any)...
+    
+    apTagId = new(ELeave) CMDBField<TInt>(KCDTIdAccessPointRecord | KCDTIdRecordTag);
+    CleanupStack::PushL(apTagId);
+    
+    
+    if ( ( (*aOrigIAPPrioritySelPolField) & KCDMaskShowType ) == 0 &&
+         ( (*aOrigIAPPrioritySelPolField) & KLinkableTag ) == 0 )
+    	{
+         //there is only a number for the IAP link in the table...
+    	*apTagId = *aOrigIAPPrioritySelPolField;
+    	}
+    else
+    	{
+    	//the IAP link is correctly set. Let's use the recordId from the value field.
+    	*apTagId = (*aOrigIAPPrioritySelPolField & KCDMaskShowRecordId) >> 8;
+    	}
+    
+    if ( !(apTagId->FindL(iSession.iOwner)) )
+    //the link level AP cannot be found. Leaving...
+        {
+        User::Leave(KErrNotFound);
+        }
+    else
+        {
+        tagId = *apTagId;
+        }
+    
+    CleanupStack::PopAndDestroy(apTagId);
+    
+    return tagId;
+    }
+
+CommsDatMapperAndValidator::TAPTypes CCDMapperIAPPrioritySelectionPolicyRecord::CheckLinkLevelAPL(TMDBElementId aElementId)
+//Assumption: an AP record always has a Tier field. 
+    {
+    CommsDatMapperAndValidator::TAPTypes ret = CommsDatMapperAndValidator::EUndefined;
+    
+    CMDBRecordLink<CCDTierRecord>* tierField = new(ELeave) CMDBRecordLink<CCDTierRecord>(aElementId | KCDTIdTier);
+    CleanupStack::PushL(tierField);
+    
+    tierField->LoadL(iSession.iOwner);
+    
+    CMDBField<TInt>* tiertagId = new(ELeave) CMDBField<TInt>(*tierField | KCDTIdRecordTag);
+    CleanupStack::PushL(tiertagId);
+    
+    tiertagId->LoadL(iSession.iOwner);
+    
+    TInt tagId = *tiertagId;
+    
+    switch (tagId)
+        {
+        case CommsDatMapperAndValidator::ENetworkLevelTierId :
+            {
+            ret = CommsDatMapperAndValidator::ENetworkLevel;
+            break;
+            }
+            case CommsDatMapperAndValidator::EIPProtoTierId :
+            {
+            ret = CommsDatMapperAndValidator::EIPProtoLevel;
+            break;
+            }
+            case CommsDatMapperAndValidator::ELinkTierId :
+            {
+            ret = CommsDatMapperAndValidator::ELinkLevel;
+            break;
+            }
+            default:
+            {
+            User::Leave(KErrNotFound);
+            }
+        };
+    
+    
+    CleanupStack::PopAndDestroy(tiertagId);
+    CleanupStack::PopAndDestroy(tierField);
+    
+    return ret;
+    }
+
+/************************* Mapper for AccessPoint Table ***************************************
+ * KCDTIdAccessPointRecord      CCDAccessPointRecord
+ *
+ * The following fields are deprecated
+ *   APGID                  CCDAccessPointRecord::iAccessPointGID
+ * 
+ * They map to new fields within the AccessPointRecord
+ *   APTier                 CCDAccessPointRecord::iTier
+ *   
+ * The following fields have some deprecated usage which is mapped 
+ * though the same field remains
+ *   APSelectionPolicy      CCDAccessPointRecord::iSelectionPolicy
+ * 
+ * 
+ */
+
+#define KCDTIdMapperAccessPointRecord    9881
+START_ATTRIBUTE_TABLE( CCDMapperAccessPointRecord, KCDTIdMapperAccessPointRecord, KCDTIdMapperAccessPointRecord)
+ 	X_REGISTER_ATTRIBUTE( CCDMapperAccessPointRecord, iTier,            TMDBLinkNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperAccessPointRecord, iMCpr,            TMDBLinkNum)
+	X_REGISTER_ATTRIBUTE( CCDMapperAccessPointRecord, iCpr,             TMDBLinkNum)
+	X_REGISTER_ATTRIBUTE( CCDMapperAccessPointRecord, iSCpr,            TMDBLinkNum)
+	X_REGISTER_ATTRIBUTE( CCDMapperAccessPointRecord, iProtocol,        TMDBLinkNum)
+	X_REGISTER_ATTRIBUTE( CCDMapperAccessPointRecord, iCprConfig,       TMDBNum)
+	X_REGISTER_ATTRIBUTE( CCDMapperAccessPointRecord, iAppSID,          TMDBNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperAccessPointRecord, iConfigAPIdList,  TMDBText)
+    X_REGISTER_ATTRIBUTE( CCDMapperAccessPointRecord, iSelectionPolicy, TMDBNum)
+    X_REGISTER_ATTRIBUTE( CCDMapperAccessPointRecord, iRecordTag, 		TMDBNum)
+END_ATTRIBUTE_TABLE()
+
+CCDMapperAccessPointRecord::CCDMapperAccessPointRecord(CMDBElement& aElement,CMDBSessionImpl& aSession, const TOperation& aOperation)
+  : CCDMapper(aElement.ElementId(), aElement, aSession, aOperation),
+    iTier(KCDTIdTier),
+	iMCpr(KCDTIdMCpr),
+	iCpr(KCDTIdCpr),
+	iSCpr(KCDTIdSCpr),
+	iProtocol(KCDTIdProtocol),
+    iCprConfig(KCDTIdCprConfig),
+    iAppSID(KCDTIdAppSID),
+	iConfigAPIdList(KCDTIdConfigAPIdList),
+	iSelectionPolicy(KCDTIdSelectionPolicy),
+	iRecordTag(KCDTIdRecordTag | KCDTIdAccessPointRecord)
+    {}    
+
+void CCDMapperAccessPointRecord::ConstructL()
+/*
+Initialise the mapper element for any read or write operation
+Only do the minimum work here as the call might be LoadL
+
+@internalTechnology
+*/
+    {   
+    // Will either be mappng the whole record or just the GID field
+
+    CMDBField<TUint32>* theGIDField = NULL;
+    
+    SetRecordId(iElement.RecordId());
+    
+    if(CommsDat::CommsDatSchema::IsRecord(iElement.ElementId()))
+        {
+        CCDAccessPointRecord& inputRecord = static_cast<CCDAccessPointRecord&>(iElement);
+
+        theGIDField = static_cast<CMDBField<TUint32>*>(&inputRecord.iAccessPointGID);
+        
+        if (!inputRecord.iSelectionPolicy.IsNull())
+            {
+            //create the link which will be valid at the time of the insertion of the IAPPrioritySelPol
+            //record
+            iSelectionPolicy.SetL(KCDTIdApPrioritySelectionPolicyRecord | inputRecord.iSelectionPolicy & KCDMaskShowRecordId);
+            }
+
+        // These elements are quite likely to be NULL
+        if (!inputRecord.iTier.IsNull())
+            {
+            iTier.SetL(inputRecord.iTier);
+            }
+        if (!inputRecord.iMCpr.IsNull())
+            {
+            iMCpr.SetL(inputRecord.iMCpr);
+            }
+        if (!inputRecord.iCpr.IsNull())
+            {
+            iCpr.SetL(inputRecord.iCpr);
+            }
+        if (!inputRecord.iSCpr.IsNull())
+            {
+            iSCpr.SetL(inputRecord.iSCpr);
+            }
+        if (!inputRecord.iProtocol.IsNull())
+            {
+            iProtocol.SetL(inputRecord.iProtocol);
+            }
+        if (!inputRecord.iCprConfig.IsNull())
+            {
+            iCprConfig.SetL(inputRecord.iCprConfig);
+            }
+        if (!inputRecord.iAppSID.IsNull())
+            {
+            iAppSID.SetL(inputRecord.iAppSID);
+            }
+        if (!inputRecord.iConfigAPIdList.IsNull())
+            {
+            iConfigAPIdList.SetL(inputRecord.iConfigAPIdList);
+            }
+        }
+    else
+        {            	
+        if ( (iElement.ElementId() & KCDMaskShowType) == KCDTIdAccessPointGID )
+        	{
+        	theGIDField = static_cast<CMDBField<TUint32>*>(&iElement);
+        	}
+        else
+        	{
+        	//selectionPolicy field...
+	        this->iSelectionPolicy.SetL(KCDTIdApPrioritySelectionPolicyRecord | static_cast<CMDBField<TUint32>&>(iElement) & KCDMaskShowRecordId);
+	        this->iSelectionPolicy.SetRecordId(iElement.RecordId());
+        	}
+        }
+
+    // Don't do validation - leave that til later.  Just copy the fields
+    if (theGIDField &&
+    	0 != (*theGIDField) &&
+    	iTier.IsNull())
+        {
+        if (Changed(*theGIDField))
+            {  
+            iTier.SetL(*theGIDField);
+            }
+        }      
+    }    
+
+void CCDMapperAccessPointRecord::PreMappingsL()
+	{
+	if (EStore == iOperation)
+		{
+		// 2.  Map the fields
+	    if ( iMCpr.IsNull() )
+	        {
+	        // this would indicate the mapper was incomplete
+	        // not trying to validate away completely pathological case where scattered fields are set
+	        
+	        //load the template AP for the Network layer form the BearerType table
+	        _LIT(KTemplateRecName,"NetworkDefaultTemplate");
+	        
+	        CCDBearerTypeRecord* templateForTheAPRec = static_cast<CCDBearerTypeRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdBearerTypeRecord));
+	        CleanupStack::PushL(templateForTheAPRec);
+	        
+	        templateForTheAPRec->iRecordName.SetMaxLengthL(KTemplateRecName().Length());
+	        templateForTheAPRec->iRecordName = KTemplateRecName();
+	            
+	        if (!templateForTheAPRec->FindL(iSession.iOwner))
+	            {
+	            User::Leave(KErrNotFound);
+	            }
+	        
+	        // Copy the fields from the template record. The recordId will be the same as the one of the 
+	        //input record
+	        iTier.SetL(templateForTheAPRec->iTier);
+	        iMCpr.SetL(templateForTheAPRec->iMCpr);
+	        iCpr.SetL(templateForTheAPRec->iCpr);
+	        iSCpr.SetL(templateForTheAPRec->iSCpr);
+	        iProtocol.SetL(templateForTheAPRec->iProtocol);
+	        //the SelectionPolicy field was set in the ConstructL function...
+	        
+	        CCDAccessPointRecord& inputRecord = static_cast<CCDAccessPointRecord&>(iElement);
+	        if (inputRecord.iRecordTag.IsNull() )
+	        //APs have to have tagIds....
+	            {
+	            iRecordTag = CommsDatMapperAndValidator::GenerateTagIdL(NetworkBaseTagId, iSession.iOwner);
+	            }
+	        
+	        CleanupStack::PopAndDestroy(templateForTheAPRec);
+	        }     
+		}
+	else if (EDelete == iOperation)
+		{
+		if (KCDMaskShowFieldType != (iElement.ElementId() & KCDMaskShowFieldType))
+			{
+			//field mapping -> change the elementId of the whole mapper object so the MaybeDeleteNodeL will delete
+			//only the given field and not the whole mapper.
+			if (KCDTIdSelectionPolicy == (iElement.ElementId() & KCDMaskShowType))
+				{
+				SetElementId(ElementId() & ~KCDMaskShowFieldType);
+				SetElementId(ElementId() | KCDTIdSelectionPolicy);
+				}
+			else
+				{
+				//the GID field is mapped into the Tier field
+				SetElementId(ElementId() | KCDTIdTier);
+				}
+			}
+		}
+	}
+    
+
+void CCDMapperAccessPointRecord::PrepareToStoreL()
+/*
+Prepare the mapper for a write operation
+
+Create any new node(s) that may be required.  
+Sometimes more than one mapper node might be needed for one input node.
+
+The mapper element will have been populated from the input element already, 
+but now complete the population where necessary following the unique set of 
+rules for this class
+
+validate the information (only where valid data is critical)
+
+The element can be populated by using information from both the input element and the database
+
+@internalTechnology
+*/
+    {     
+    // Create new node if necessary (only one new node in this case) and only when the input element is a record
+    iSession.MaybeCreateNodeL((CMDBElement&)*this);
+    if ( (iElement.ElementId() & KCDNewRecordRequest == KCDNewRecordRequest) &&
+    	 (iElement.ElementId() & KCDMaskShowFieldType) ==  KCDMaskShowFieldType )
+    	{
+    	iElement.SetRecordId(this->RecordId());
+    	}
+
+    // Check that the tier matches the default tier (leave if it doesn't)
+    CMDBField<TUint32>* theGIDField = NULL;
+        
+    if(CommsDat::CommsDatSchema::IsRecord(iElement.ElementId()))
+        {
+        CCDAccessPointRecord& inputRecord = static_cast<CCDAccessPointRecord&>(iElement);
+
+        theGIDField = static_cast<CMDBField<TUint32>*>(&inputRecord.iAccessPointGID);
+        }
+    else
+        {
+        if ( (iElement.ElementId() & KCDMaskShowType) == KCDTIdAccessPointGID )
+        	{
+        	theGIDField = static_cast<CMDBField<TUint32>*>(&iElement);
+        	}
+        }
+    
+    // 1. lookup defaultTier record from global settings and check it matches.
+    if (NULL == theGIDField ||
+    	0 == *theGIDField)
+    	{
+    	//GID field is not filled in the record so let's try to read the tier field in the mapped AP with the same
+    	//recordId as the one from the client...
+    	
+    	//tier link in the AP record
+    	CMDBRecordLink<CCDTierRecord>* apTierField = new(ELeave) CMDBRecordLink<CCDTierRecord>(KCDTIdTier);
+    	CleanupStack::PushL(apTierField);
+    	apTierField->SetRecordId(iElement.RecordId());
+    	
+    	//tier link in the GS record
+    	CMDBRecordLink<CCDTierRecord>* gsTierField = new(ELeave) CMDBRecordLink<CCDTierRecord>(KCDTIdDefaultTier);
+    	CleanupStack::PushL(gsTierField);
+    	gsTierField->SetRecordId(1);
+    	
+    	apTierField->LoadL(iSession.iOwner);
+    	gsTierField->LoadL(iSession.iOwner);
+    	
+    	if ( *gsTierField != ((*apTierField & KCDMaskShowRecordId) >> 8) )
+    		{
+    		//this is not a network level AP -> leaving
+    		User::Leave(KErrArgument);
+    		}
+    	CleanupStack::PopAndDestroy(gsTierField);
+    	CleanupStack::PopAndDestroy(apTierField);
+    	}
+    else
+    	{
+    	CheckIsSnapL(*theGIDField); // returned default tier id is not used here
+    	}
+    }    
+
+
+
+TBool CCDMapperAccessPointRecord::NeedsMapping(CMDBElement& aElement)
+// NB it is correct that the fields listed here are different from the fields in the Mapped() function 
+    {
+    if( CommsDat::CommsDatSchema::IsRecord(aElement.ElementId()) )
+        {
+        CCDAccessPointRecord& ap = static_cast<CCDAccessPointRecord&>(aElement);
+        if (ap.iTier.IsNull() )
+            {
+            // either reading into an empty record or storing and haven't set the tier so map
+            return ETrue; 
+            }
+
+        return EFalse;
+        }
+        
+        
+    if( (aElement.ElementId() & KCDMaskShowType) == KCDTIdAccessPointGID ||
+    	(aElement.ElementId() & KCDMaskShowType) == KCDTIdSelectionPolicy )
+        {
+        return ETrue;
+        }
+
+    return EFalse;
+    }
+
+
+TBool CCDMapperAccessPointRecord::Mapped(TMDBElementId aElementId)
+// Lists the fields in this record that will be handled by the mapper not the caller
+    {
+    TInt fieldTypeId = aElementId & KCDMaskShowType;
+
+    switch(fieldTypeId)
+		{
+ 		case KCDTIdAccessPointGID :
+        case KCDTIdTier :
+        case KCDTIdMCpr :
+        case KCDTIdCpr :
+        case KCDTIdSCpr :
+        case KCDTIdProtocol :
+        case KCDTIdCprConfig :
+        case KCDTIdAppSID :
+        case KCDTIdConfigAPIdList :
+		case KCDTIdSelectionPolicy :
+   		   {
+           return ETrue;
+	       }
+        }
+	return EFalse;
+    }
+
+//Delete the previously stored selectionPolicy field...
+/*virtual*/ void CCDMapperAccessPointRecord::FinalPreparationsL()
+    {
+    CMDBRecordLink<CCDSelectionPolicyRecordBase>* selectionPolicy = new(ELeave) CMDBRecordLink<CCDSelectionPolicyRecordBase>(KCDTIdSelectionPolicy);
+    selectionPolicy->SetRecordId(RecordId());
+    
+    selectionPolicy->DeleteL(iSession.iOwner);
+    }
+
+
+TMDBElementId CCDMapper::CheckIsSnapL(TMDBElementId aInputId)
+    {
+    // first find the default tier record
+    CMDBRecordLink<CCDTierRecord> *tierLinkField = new(ELeave) CMDBRecordLink<CCDTierRecord>(KCDTIdGlobalSettingsRecord | KCDTIdDefaultTier | KCDGlobalSettingsRecordId); 
+    CleanupStack::PushL(tierLinkField);
+    
+    tierLinkField->LoadL(iSession.iOwner);
+    
+    TMDBElementId defaultTierId = (tierLinkField->iLinkedRecord->ElementId()) & KCDMaskShowRecordTypeAndId;
+    
+    // now prime the same container with aId and check we get to the same tier record id
+    tierLinkField->SetL(aInputId);
+
+    TMDBElementId resolvedInputId = CommsDatSchema::GetLinkIdL(iSession.iOwner, tierLinkField->ElementId(), tierLinkField->GetL(), KCDTIdTierRecord/*, NULL*/);
+
+    if (defaultTierId != resolvedInputId)
+        {
+        __FLOG_STATIC3(KLogComponent, KCDErrLog,
+                       _L("CCDMapper::CheckIsSnapL() - iGID <%08x> resolves to <%08x> not to the default (SNAP) Tier <%08x>"),
+                       aInputId, resolvedInputId, defaultTierId);
+      
+        User::Leave(KErrArgument);
+        }
+   
+    CleanupStack::PopAndDestroy(tierLinkField); 
+    
+    return defaultTierId;
+    }
+
+
+
+void CCDMapperAccessPointRecord::MapResultsL()
+/*
+Map results to client element following mapping rules
+
+only the GID and SelPol field need mapping
+
+@internalComponent
+*/
+    {    
+    CMDBField<TUint32>* gidInputElement = NULL;
+    CMDBRecordLink<CCDSelectionPolicyRecordBase>* selectionPolicy;
+    
+    if(CommsDat::CommsDatSchema::IsRecord(iElement.ElementId()))
+        {
+        CCDAccessPointRecord& inputRecord = static_cast<CCDAccessPointRecord&>(iElement);
+        gidInputElement = static_cast<CMDBField<TUint32>*>(&inputRecord.iAccessPointGID);
+        selectionPolicy = static_cast<CMDBRecordLink<CCDSelectionPolicyRecordBase>*>(&inputRecord.iSelectionPolicy);
+        
+        TInt mappedLinkValue = static_cast<TInt>(iSelectionPolicy);
+        if (mappedLinkValue)
+        	{
+        	*selectionPolicy = KCDTIdIapPrioritySelectionPolicyRecord | (mappedLinkValue & KCDMaskShowRecordId);
+        	}
+        }
+    else
+        {
+        if( (iElement.ElementId() & KCDMaskShowType) == KCDTIdAccessPointGID)
+        	{
+        	gidInputElement=static_cast<CMDBField<TUint32>*>(&iElement);
+        	}
+        else
+        	{
+        	//selection policy field mapping
+        	TInt selPolVal = static_cast<TInt>(iSelectionPolicy);
+        	if (selPolVal)
+        		{
+	        	CMDBField<TInt>* inputSelPolField = static_cast<CMDBField<TInt>*>(&iElement);
+	        	inputSelPolField->SetL(KCDTIdIapPrioritySelectionPolicyRecord | selPolVal & KCDMaskShowRecordId);
+	        	Sync(*inputSelPolField);
+        		}
+        	}
+        }
+    
+    // Tier may not be default, but it's still ok to copy tier id to GID 
+    // Though remember only default tier can be stored via a mapped access point
+    if ( (CommsDat::CommsDatSchema::IsRecord(iElement.ElementId())) ||
+    	 ((iElement.ElementId() & KCDMaskShowType) == KCDTIdAccessPointGID) &&
+    	!iTier.IsNull() )
+        {
+        gidInputElement->SetL(iTier);
+        Sync(*gidInputElement);
+        }
+    }
+
+
+#endif // SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+
+
+		
+//EOF
+
+
+
+
+
+
+
+
+
+
+
+
+