diff -r 000000000000 -r dfb7c4ff071f commsfwtools/preparedefaultcommsdatabase/src/CommsDatSessionImpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commsfwtools/preparedefaultcommsdatabase/src/CommsDatSessionImpl.cpp Thu Dec 17 09:22:25 2009 +0200 @@ -0,0 +1,1654 @@ +// 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: +// Implementation of comms database session functions +// dealing with : +// session creation and destruction +// data version checking +// transaction management +// containment of helper classes for notification, mapping, database interaction etc +// +// + +/** + @file + @internalComponent +*/ + + +#include "CommsDatInternalDefs.h" +//#include +#include +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include +#endif + +/** + Last 4 digits of binary UID. This number has no meaning, + but must be something that is very unlikely to be used by real + fields in a database. +*/ +#define MEANINGLESS_NUMBER 0x4DDB + +using namespace CommsDat; +using namespace CommsDatInternal; + + + + +// +// Utilities for comparing items in arrays + +TInt InsertNode(const TUint32& aFirst, const TUint32& aSecond) +/* +Utility function to find node in array +@internalComponent +*/ + { + TUint mask = KCDMaskShowField | KCDUtilityFlag; + + if ((aFirst & mask ) == (aSecond & mask)) + return 0; + + if ((aFirst & mask) < (aSecond & mask)) + return -1; + + return 1; + } + +TBool FindNode(const TUint32& aFirst, const TUint32& aSecond) +/* +Utility function to find node in array +@internalComponent +*/ + { + TUint mask = KCDMaskShowField | KCDUtilityFlag; + return (aFirst & mask ) == (aSecond & mask); + } + + +TBool CompareElements(const CMDBElement& aFirst, const CMDBElement& aSecond) +/* +Utility function to compare elements in array +@internalComponent +*/ + { + return &aFirst == &aSecond; + } + + +TInt InsertElements(const CMDBElement& aFirst, const CMDBElement& aSecond) +/* +Utility function to allow insertion of elements in array +@internalComponent +*/ + { + if (&aFirst == &aSecond) + return 0; + if (&aFirst < &aSecond) + return -1; + return 1; + } + +TBool CompareElementsById(const CMDBElement& aFirst, const CMDBElement& aSecond) +/* +Utility function to compare elements in array by matching Table, Column and RecordId +@internalComponent +*/ + { + return (aFirst.ElementId() & KCDMaskShowField) == (aSecond.ElementId() & KCDMaskShowField); + } + + + +// + + + +CMDBSessionImpl::CMDBSessionImpl(CMDBSession& aOwner) +/* +Constructor +@internalComponent +*/ + : iOwner(aOwner), + iReadAttributeMask(KCDMaskShowReadAttributes), + iWriteAttributeMask(KCDMaskShowReadWriteAttributes) + { + } + + +CMDBSessionImpl::~CMDBSessionImpl() +/* +Destructor + +@internalComponent +*/ + { + Close(); + } + + + + +TInt CMDBSessionImpl::ConstructL( TVersion aRequiredVersion ) +/* +Open a session with the storage server and compare data versions + +The MetaDatabase always attempts to support the required version. If the versions match, +KErrNone will be returned. If the versions are not the same, but the requested version +is supported, a warning code will be returned. Otherwise an error will be +returned. The latest version is returned in the aLatestVersion parameter for information + +@internalComponent +*/ + { + if (iCommsStorage) + { + return KErrNone; + } + + __FLOG_STATIC1(KLogComponent, KCDInfoLog, _L("*** CMDBSessionImpl::ConstructL() constructing session object object <%08x>"), this); + + EstablishVersionL(aRequiredVersion); + + // Connect to the repository + iCommsStorage = ::CRepository::NewL(KCDCommsRepositoryId); + + // register for events +#ifndef __TOOLS2__ + TInt err = iCommitSeqProperty.Attach(KUidCommsDatStatusEvent, KCommsDatStatusEventCommitSeq); + + if (err != KErrNone) + { + __FLOG_STATIC1(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::ConstructL() failed with error <%d>"), err); + User::Leave(err); + } +#endif + + return KErrNone; + } + + +void CMDBSessionImpl::Close() +/* +Close session with storage server. +No session required with Central repository + +@internalComponent +*/ + { +#ifndef __TOOLS2__ + TRAPD( + err, + + // Don't signal any roll-back, the reason we're performing a roll-back is because + // the session is being CLOSED. + NotifierL()->SuppressRollBackEvents(); + + RollbackTransactionL(); + + NotifierL()->NotifyClients(TCDNotifiableEvent::EClose); + ); + err = err; // suppress "unused-var" warning + + delete iNotifier; + iNotifier=NULL; +#endif + +#ifdef __TOOLS2__ + if (iCommsStorage) + { + iCommsStorage->Flush(); + } +#endif + delete iCommsStorage; + iCommsStorage=NULL; + + iCommitSeqProperty.Close(); + } + + + +TBool CMDBSessionImpl::UsingLatestVersion() +/* +Check the flag that indicates whether using latest version + +@internalComponent +*/ + { + return iUsingLatestVersion; + } + + + +void CMDBSessionImpl::EstablishVersionL(TVersion aRequiredVersion) +/* +Check the version in use at the moment and set a flag if using latest version +Return an error code KErrDeprecated if version is deprecated +Return KErrNone if the version is current + +MAINTENANCE - this function needs updating whenever the latest version changes + +@internalComponent +*/ + { +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + if ( aRequiredVersion.iMajor == KCDVersion1_2.iMajor && + aRequiredVersion.iMinor == KCDVersion1_2.iMinor && + aRequiredVersion.iBuild == KCDVersion1_2.iBuild ) + { + iClientsDataSetVersion = aRequiredVersion; + iUsingLatestVersion = ETrue; + + __FLOG_STATIC3(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::EstablishVersionL() Current dataset version <%d.%d.%d> in use. Mapping disabled"), KCDVersion1_2.iMajor, KCDVersion1_2.iMinor, KCDVersion1_2.iBuild); + + return; + } + else if( (aRequiredVersion.iMajor == KCDVersion1_1.iMajor && + aRequiredVersion.iMinor == KCDVersion1_1.iMinor && + aRequiredVersion.iBuild == KCDVersion1_1.iBuild) || + //the orig KCDLatesVersion was (0,0,0) + (aRequiredVersion.iMajor == 0 && + aRequiredVersion.iMinor == 0 && + aRequiredVersion.iBuild == 0) ) + { + iClientsDataSetVersion = KCDVersion1_1; + iUsingLatestVersion = EFalse; + + __FLOG_STATIC3(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::EstablishVersionL() Deprecated dataset version <%d.%d.%d> in use. Mapping enabled"), aRequiredVersion.iMajor, aRequiredVersion.iMinor, aRequiredVersion.iBuild); + + return; + } +#else + if( (aRequiredVersion.iMajor == KCDVersion1_1.iMajor && + aRequiredVersion.iMinor == KCDVersion1_1.iMinor && + aRequiredVersion.iBuild == KCDVersion1_1.iBuild) || + //the orig KCDLatesVersion was (0,0,0) + (aRequiredVersion.iMajor == 0 && + aRequiredVersion.iMinor == 0 && + aRequiredVersion.iBuild == 0) ) + { + iClientsDataSetVersion = KCDVersion1_1; + iUsingLatestVersion = ETrue; + + __FLOG_STATIC3(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::EstablishVersionL() Current dataset version <%d.%d.%d> in use. Mapping disabled"), aRequiredVersion.iMajor, aRequiredVersion.iMinor, aRequiredVersion.iBuild); + + return; + } +#endif + + // MAINTENANCE - as versions are deprecated, allow them to still be used and return KCDDeprecatedVersion here. + + __FLOG_STATIC3(KLogComponent, KCDErrLog, _L("*** CMDBSessionImpl::EstablishVersionL() Requested dataset version <%d.%d.%d> not supported"), aRequiredVersion.iMajor, aRequiredVersion.iMinor, aRequiredVersion.iBuild); + + User::Leave(KErrNotSupported); + + return; + } + + +// +// Accessors + +TVersion CMDBSessionImpl::LatestVersion() +/* +Lookup latest data format version + +@Deprecated +@internalComponent +*/ + { + return KCDCurrentVersion; + } + + +TVersion CMDBSessionImpl::VersionInUse() +/* +Lookup data format version currently in use by client + +@internalComponent +*/ + { + return iClientsDataSetVersion; + } + + +CRepository* CMDBSessionImpl::StorageL() +/* +Return Storage class for Comms data + +@internalComponent +*/ + { + if (! iCommsStorage) + { + iCommsStorage = ::CRepository::NewL(KCDCommsRepositoryId); + } + return iCommsStorage; + } + + +#ifndef __TOOLS2__ +CCDNotifier* CMDBSessionImpl::NotifierL() +/* +return notifier object, creating it if necessary. + +@internalComponent +*/ + { + if (! iNotifier) + { + iNotifier = ::CCDNotifier::NewL(*this); + } + return iNotifier; + } +#endif + + + + +// +// TRANSACTIONS WITH THE DATABASE SERVER +// + +TBool CMDBSessionImpl::MaybeOpenTransactionL() +/* +Start transaction with storage server if available + +Returns ETrue if opens transaction +Returns EFalse if already in transaction + +@internalComponent +*/ + { + TBool ownTransaction = EFalse; + + if ( ! iInTransaction ) + { + TInt err = StorageL()->StartTransaction(CRepository::EReadWriteTransaction); + + if (err != KErrNone) + { + __FLOG_STATIC1(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::MaybeOpenTransactionL() - CentralRepository::StartTransactionL() failed with err = %d"), err); + User::Leave(err); + } + else + { + iInTransaction = ETrue; + ownTransaction = ETrue; + } + } + + return ownTransaction; + } + + + + +void CMDBSessionImpl::RollbackTransactionL() +/* +Explicitly request rollback of transaction restoring database state to before transaction started. + +@internalComponent +*/ + { + if (iInTransaction) + { + StorageL()->RollbackTransaction(); + + __FLOG_STATIC(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::RollbackTransactionL() Has rolled back storage server Transaction ")); + + iInTransaction = EFalse; + +#ifndef __TOOLS2__ + //delete notifications if there are any + NotifierL()->ClearPubSubNotifications(); + + // Notify any clients. + NotifierL()->NotifyClients(TCDNotifiableEvent::ERollback); +#endif + } + } + + +TInt CMDBSessionImpl::MaybeCommitTransactionL(TBool aOwnTransaction, CMDBElement* aElement, TInt aErr) +/* + +Commit transaction if outstanding and owned by caller + +Rollback transaction if an error has occurred + +Mapping and notification tasks may be required after commit + + Load/Find -> map & sync + Update -> map + Store/Modify -> sync & notify + Delete -> notify + +@internalComponent +*/ + { + __FLOG_STATIC3(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::MaybeCommitTransactionL() aOwnTransaction = %b, aElementId = %08x, Err = %d"), aOwnTransaction, aElement ? aElement->ElementId() : 0, aErr); + + // Stop compiler complaining abot unused variables in UREL builds. + (void)aElement; + + if (aErr != KErrNone) + { + __FLOG_STATIC2(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::MaybeCommitTransactionL() Commit transaction for element <%08x> failed with error <%d>. The transaction will be rolled back"), aElement ? aElement->ElementId() : 0, aErr); + RollbackTransactionL(); + User::Leave(aErr); + } + + TInt err(KErrNone); + + if ( aOwnTransaction && iInTransaction ) + { + TUint32 errLoc; + +#ifndef __TOOLS2__ + // Update the global commit sequence. If we can't fetch the current one then we set it to the FastCounter() as a best effort + // signal of change to observers + TInt currCommitSeq; + if(iCommitSeqProperty.Get(currCommitSeq) != KErrNone) + { + currCommitSeq = User::FastCounter(); + } + iCommitSeqProperty.Set(currCommitSeq + 1); +#endif + + err = StorageL()->CommitTransaction(errLoc); + + if (err != KErrNone) + { + __FLOG_STATIC2(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::MaybeCommitTransactionL() CentralRepository::CommitTransaction failed with err = %d at %08x"), err, errLoc); + + RollbackTransactionL(); + + User::Leave(err); + } + + + +#ifndef __TOOLS2__ + //notify any changes via pubsub if necessary + NotifierL()->NotifyAllChanges(); + + // Notify any clients. + + /* + NOTE: Documented or not, our Licensees expect EUnlock notification to be returned if + CommitTransaction didn't have anything to commit (probably because user container remained unchanged or + the user used it as a read transaction). So we are to notify with ECommit, if and only the database actually changed. + + This behaviour SHOULD not be changed without a BC break. Death, Destruction, rage, pillage and horror will follow if not.. + */ + if(errLoc > 0) + { + NotifierL()->NotifyClients(TCDNotifiableEvent::ECommit); + } + else + { + //errLoc will be 0 if the db wasn't changed.. + NotifierL()->NotifyClients(TCDNotifiableEvent::EUnlock); + } +#endif + + iInTransaction = EFalse; + } + + return aErr; + } + + +TBool CMDBSessionImpl::IsInTransaction() +/* +Query if transaction is already underway in this session + +@internalComponent +*/ + { + //__FLOG_STATIC1(KLogComponent, KCDInfoLog, _L("IsInTransaction - returning = %b "), iInTransaction ); + + return iInTransaction; + } + + +void CMDBSessionImpl::SetAttributeMask(TMDBAttributeFlags aAttributeMask) +/* +CLEAR flags from read and write attribute masks so that attributes are ignored + +@internalComponent +*/ + { + TUint32 tmpWrite = (~aAttributeMask & KCDMaskShowReadWriteAttributes); + iWriteAttributeMask &= tmpWrite; + + TUint32 tmpRead = (~aAttributeMask & KCDMaskShowReadAttributes); + iReadAttributeMask &= tmpRead; + + __FLOG_STATIC3(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::SetAttributeMask() aAttributeMask = %08x, iReadAttributeMask now = %08x. iWriteAttributeMask now = %08x"), aAttributeMask, iReadAttributeMask, iWriteAttributeMask); + } + + +TBool CMDBSessionImpl::IsSetAttributeMask(TMDBAttributeFlags aAttributeMask) +/* +Check flags in read and write attribute masks as requested + +@internalComponent +*/ + { + TUint32 currentMask = (iWriteAttributeMask | iReadAttributeMask); + TBool retval = ((currentMask & (~aAttributeMask & KCDMaskShowAttributes)) == currentMask); + return retval; + } + + + +void CMDBSessionImpl::ClearAttributeMask(TMDBAttributeFlags aAttributeMask) +/* +SET flags in read and write attribute masks so that attributes are obeyed + +@internalComponent +*/ + { + TUint32 tmpWrite = (aAttributeMask & KCDMaskShowReadWriteAttributes); + iWriteAttributeMask |= tmpWrite; + + TUint32 tmpRead = (aAttributeMask & KCDMaskShowReadAttributes); + iReadAttributeMask |= tmpRead; + + __FLOG_STATIC3(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::ClearAttributeMask() aAttributeMask = %08x, iReadAttributeMask now = %08x. iWriteAttributeMask now = %08x"), aAttributeMask, iReadAttributeMask, iWriteAttributeMask); + } + + +TMDBAttributeFlags CMDBSessionImpl::GetWriteAttributeMask() +/* +Return current write attribute mask + +@internalComponent +*/ + { + return iWriteAttributeMask; + } + + +TMDBAttributeFlags CMDBSessionImpl::GetReadAttributeMask() +/* +Return current read attribute mask + +@internalComponent +*/ + { + return iReadAttributeMask; + } + + +void CMDBSessionImpl::ReadAllowedL(TMDBElementId aElementId) +/* +If one or more read attributes are SET in the aElementId and in the write attribute mask, +the session does not have permission to read this element. +*/ + { + if ( (iReadAttributeMask & (aElementId & KCDMaskShowReadAttributes) ) ) + { + __FLOG_STATIC1(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::ReadAllowed() This client does not have the correct access attributes to view Element <%08x>"), aElementId); + User::Leave(KErrPermissionDenied); + } + } + +void CMDBSessionImpl::WriteAllowedL(TMDBElementId aElementId) +/* +If one or more write attributes are SET in the aElementId and in the write attribute mask, +the session does not have permission to write or update this element. +*/ + { + if ( (iWriteAttributeMask & (aElementId & KCDMaskShowReadWriteAttributes) ) ) + { + __FLOG_STATIC1(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::WriteAllowed() This client does not have the correct access attributes to write Element <%08x>"), aElementId); + User::Leave(KErrPermissionDenied); + } + } + +void CMDBSessionImpl::DeleteAllowedL(TMDBElementId aElementId) +/* +If one or more write attributes are SET in the aElementId and in the write attribute mask, +the session does not have permission to delete this element. + +However ECDNoWriteButDelete must be ignored in the writeAttributeMask as it is anomalous +for BC reasons +*/ + { + if ( iWriteAttributeMask & (aElementId & (KCDMaskShowReadWriteAttributes & ~ECDNoWriteButDelete)) ) + { + __FLOG_STATIC1(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::DeleteAllowed() This client does not have the correct access attributes to delete Element <%08x>"), aElementId); + User::Leave(KErrPermissionDenied); + } + } +TInt CMDBSessionImpl::LoadNodeAttributesL(TMDBElementId& aElementId) +/* +Find out appropriate attributes for this node id by checking specified node +and gathering attributes from parent nodes if aElementId does not exist in the database. + +Return KErrNone if the node does exist and gather attributes from the existing node into aElementId +Return KErrNotFound if node does not exist, but gather attributes from parent nodes anyway (if they exist) + +Leave with KErrPermissionDenied if database forbids access to any element. + +@internalComponent +*/ + { + ASSERT(aElementId); + + TInt retval(KErrNotFound); + + if(!(CommsDatSchema::IsNewRecordRequest(aElementId) || CommsDatSchema::IsNewColumnRequest(aElementId))) + { + retval = FindElementInDatabaseL(aElementId); + } + + if ( retval == KErrNotFound && ! CommsDatSchema::IsTable(aElementId) ) + { + // This must be a new field or node so gather attributes from parent nodes, + // Report if don't find parent Record or Table nodes, + TInt err(GatherParentAttributesL(aElementId)); + + if ( err != KErrNone ) + { + // don't worry about this, but just log it as might be of interest + __FLOG_STATIC2(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::LoadNodeAttributes for id %08x. GatherParentAttributesL returned err %d"), aElementId, err); + } + } + + return retval; + } + + +TInt CMDBSessionImpl::GatherParentAttributesL(TMDBElementId& aElementId) +// Get table attributes for any record or column node +// Get Record and Column attributes for any field + +// Do not call this function to find a Table placeholder and element directly + +// Leave with KErrAccessDenied if cannot access a node. +// return with KErrNotFound if expected parent node is not present + +// May leave with other errors from repository +// May return with other error codes from repository + { + ASSERT(aElementId); + + TInt retval(KErrNotFound); + TMDBElementId id(aElementId); + + if ( CommsDatSchema::IsNode(aElementId) ) + { + // element is a record or column, or table, so load Table attributes + id |= (KCDMaskShowRecordId | KCDMaskShowFieldType); + + retval = FindElementInDatabaseL(id); + + aElementId |= (id & KCDMaskShowAttributes); + } + else + { + // Element is a field so get attributes from the parent record + id = aElementId | KCDMaskShowFieldType; + + retval = FindElementInDatabaseL(id); + + aElementId |= (id & KCDMaskShowAttributes); + + // Finally, get extra attributes from parent column node if the node exists (it may not) + id = aElementId | KCDMaskShowRecordId; + + if ( KErrNone == FindElementInDatabaseL(id) ) + { + aElementId |= (id & KCDMaskShowAttributes); + } + } + return retval; + } + + +// +// NODE MANAGEMENT FUNCTIONS ... +// + +TInt CMDBSessionImpl::FindElementInDatabaseL(TMDBElementId& aElementId) +/* +Locates a single element in the database, retrieving the full id of the element including its attributes + +Only locates one field, node or placeholder + +returns EFalse if the element is not found +returns ETrue if the element is found + +If the client process does not have the capabilities to read this element +this function will leave with KErrPermissionDenied + +*/ + { + ASSERT(aElementId); + + // Find this element with any attributes so only specify the , + // but don't want placeholder.as well as node so pay attention to the utility flag + TUint32 mask(KCDUtilityFlag | KCDMaskShowField); + + //__FLOG_STATIC2(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::LocateElementInDatabaseL for id %08x. CRepository::FindL using mask %08x"), aElementId, mask); + + RArray ids; + CleanupClosePushL(ids); + + // set the utility flag so don't find placeholder. Will leave if permission denied + TInt retval = StorageL()->FindL((aElementId & ~KCDUtilityFlag), mask, ids); + + if (ids.Count()) + { + // element already exists in database so set attributes + aElementId = (aElementId & ~KCDMaskShowAttrAndRes) | (ids[0] & KCDMaskShowAttributes); + +#ifdef __DEBUG + if (ids.Count() > 1) + { + // Must not find more than one this would be a fundamental error! + __FLOG_STATIC3(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::LocateElementInDatabase() for id <%08x>. CRepository::FindL with mask %08x returned %d entries. Should only be 1"), aElementId, mask, ids.Count()); + } +#endif + } + + CleanupStack::PopAndDestroy(&ids); + + if ( retval != KErrNone && retval != KErrNotFound ) + { + __FLOG_STATIC2(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::LocateElementInDatabase() for id <%08x>. CRepository::FindL. Returned err was %d"), aElementId, retval); + } + + return retval; + } + + +TInt CMDBSessionImpl::LoadElementAttributesL(TMDBElementId& aElementId) +/* +Find out appropriate attributes for this element id by checking nodes + + If element is table just look for corresponding table node + If element is record, get attributes from existing record node or from table node if record doesn't yet exist + If element is column, get attributes from existing column node or from table node if column doesn't yet exist + + If element is field, get attributes from existing record and column too, where that has been set. + + If node does not exist, return KErrNotFound + + But if element is single field and does not exist set attributes from the node and return KErrNone unless parent + node doesn't exist in which case return KErrNotFound + + In non-user-defined record types, column nodes are only set when attributes differ from general table attributes. + In user defined record types, column nodes are always set. + +@internalComponent +*/ + { + TInt retval(KErrNotFound); + + if( aElementId ) + { + RArray ids; + CleanupClosePushL(ids); + + // first look for the element itself directly... + + // find this element with any attributes, but don't find placeholders. + TUint32 mask(KCDUtilityFlag | KCDMaskShowField); + + // __FLOG_STATIC2(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::LoadElementAttributes for id %08x. CRepository::FindL using mask %08x"), aElementId, mask); + + retval = StorageL()->FindL((aElementId & ~KCDUtilityFlag), mask, ids); + + if (ids.Count() > 1) + { + // don't expect to find more than one !! + __FLOG_STATIC3(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::LoadElementAttributes() for id <%08x>. CRepository::FindL() with mask <%08x> returned %d entries. Should only be 1"), aElementId, mask, ids.Count()); + } + + + if ( retval != KErrNone && CommsDatSchema::IsNode(aElementId)) + { + if (retval != KErrNotFound) + { + __FLOG_STATIC3(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::LoadElementAttributes for id %08x. CRepository::FindL. mask %08x Returned err was %d"), aElementId, mask, retval); + } + } + else + { + retval = KErrNotFound; + + if (ids.Count()) + { + // node already exists so set attributes + aElementId = (aElementId & ~KCDMaskShowAttrAndRes) | (ids[0] & KCDMaskShowAttributes); + retval = KErrNone; + } + else + { + // Need to gather attributes from parent nodes to ensure new element is created appropriately + // but error is still KErrNotFound + + // __FLOG_STATIC2(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::LoadElementAttributes for id %08x. CRepository::FindL with mask %08x returned no entries. Checking parent nodes"), aElementId, mask); + + TMDBElementId id(aElementId); + + if ( CommsDatSchema::IsRecord(aElementId) || CommsDatSchema::IsColumn(aElementId) ) + { + // Get attributes from parent table + + id |= (KCDMaskShowRecordId | KCDMaskShowFieldType); + + // Last step in (potentially) recursive call chain (note we deliberately drop the KErrNone return value). + if (LoadElementAttributesL(id) == KErrNone) + { + aElementId |= (id & KCDMaskShowAttributes); + } + } + else if ( !CommsDatSchema::IsTable(aElementId) ) + { + // This is a single field. + // Get attributes from the parent record... + + id = aElementId | KCDMaskShowFieldType; + + if ( LoadElementAttributesL(id) == KErrNone ) + { + aElementId |= (id & KCDMaskShowAttributes); + + // ...and might need to get attributes from the column node too..., + id = aElementId | KCDMaskShowRecordId; + if ((retval = LoadElementAttributesL(id)) == KErrNone) + { + aElementId |= (id & KCDMaskShowAttributes); + } + } + } + } + } + + if ( retval != KErrNone && retval != KErrNotFound ) + { + __FLOG_STATIC3(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::LoadElementAttributesL() for id <%08x> CRepository::FindL with mask %08x returned err %d"), aElementId, mask, retval); + } + + CleanupStack::PopAndDestroy(&ids); + } + + return retval; + } + +void CMDBSessionImpl::SetNodeIdL(TMDBElementId& aElementId, TMDBElementId aNodeTypeMask, TMDBElementId aInitialId, TMDBElementId aMaxId, TInt aMaxVal) +/* +Set id to a new node in the database recording the item's attributes etc. +Will leave with KErrOverflow if there is no more space to create a new item +*/ + { + // First see which placeholder nodes already exist at this level + // placeholder nodes will never have any attributes set and will always be readable by those who can write to central repository + + __FLOG_STATIC2(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::SetNodeIdL() for id <%08x> CRepository::FindL using mask <%08x>"), aElementId, aNodeTypeMask); + + RArray ids; + CleanupClosePushL(ids); + + TInt err = StorageL()->FindL(aElementId, aNodeTypeMask, ids); + + + //Ids now contains all the nodes for all the tables, Filter out those only for generic tables + if(aMaxVal == KCDMaxUserDefTables) + { + TInt i(ids.Count()); + while ( i > 0 ) + { + i--; + if((ids[i] & KCDMaskShowRecordType) < KCDInitialUDefRecordType) + { + ids.Remove(i); + } + } + ids.Compress(); + } + + if (ids.Count() >= aMaxVal) + { + err = KErrOverflow; + } + + if (err != KErrNone && err != KErrNotFound) + { + __FLOG_STATIC1(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::SetNodeIdL for id %08x. CRepository::FindL returned no entries. Should have found 1"), aElementId); + + CleanupStack::PopAndDestroy(&ids); + User::Leave(err); + } + else + { + while ( ids.Count() > 0 && (ids[ids.Count() - 1] & aMaxId) == aMaxId ) + { + ids.Remove(ids.Count() - 1); + ids.Compress(); + } + + + if( ids.Count() == 0 || + ( ids.Count() == 1 && (ids[0] & aMaxId) == 0 ) ) // just default entry + { + if(aMaxVal == KCDMaxUserDefTables) + { + //if for generic table request + aElementId |= KCDInitialUDefRecordType; + } + else + { + aElementId |= aInitialId; + } + } + else if (ids.Count() == 1) + { + TUint32 temp = (ids[0] & aMaxId); + temp += aInitialId; + /** + if the remaining recordId is FE (AccessPointPrioritySelectionPolicy record) then the new record id + should be 1 and not FF. + */ + if (temp == aMaxId) + { + temp = KCDInitialRecordId; + } + aElementId |= temp; + } + else + { + TMDBElementId testId = (ids[ids.Count() - 1] & aMaxId) + aInitialId; + + if ( testId < aMaxId ) + { + // assign next free id at end of list + aElementId |= testId; + } + else + { + testId = ids[0] & aMaxId; + + if ( testId > aInitialId ) + { + // assign free id from the beginning of the list + aElementId |= aInitialId; + } + else + { + // assign first free id found in the list + for (TInt i = 0; i < ids.Count() -1; i++) + { + testId = (ids[i] & aMaxId) + aInitialId; + + if ( (ids[i+1] & aMaxId) > testId ) + { + aElementId |= testId; + break; + } + } + } + } + } + + __FLOG_STATIC1(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::SetNodeIdL() successfully set aElementId to <%08x>"), aElementId); + + CleanupStack::PopAndDestroy(&ids); + } + } + + +void CMDBSessionImpl::CreatePlaceholderL(TMDBElementId& aElementId, TMDBElementId aNodeTypeMask, TDesC& aTableName) +/* +Create placeholdertype info node which must never have any attributes set + + Table <0> Int + Record <0> Int + Column <0> Int +*/ + { + TInt err(KErrNone); + // always might need to create a table placeholder - create one if client is storing + // first record or column in a table as well as explicitly creating the table + TUint32 id = (aElementId & KCDMaskShowRecordType) | (KCDNewTableRequest & ~KCDChangedFlag) | KCDUtilityFlag ; + + RArrayids; + CleanupClosePushL(ids); + + TUint32 tablePlaceholder = id | KCDMaskShowFieldType | KCDMaskShowRecordId | KCDUtilityFlag; + if (KErrNotFound == StorageL()->FindL(tablePlaceholder, KCDCenRepNoMask, ids)) + { + err = StorageL()->Create(tablePlaceholder, MEANINGLESS_NUMBER); + if (err != KErrNone) + { + __FLOG_STATIC3(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::CreatePlaceholderL() for id <%08x>, prepared id <%08x> CRepository::Create() for missing table returned %d"), aElementId, tablePlaceholder, err); + } + else + { + if (aNodeTypeMask != KCDMaskShowRecordType) + { + TUint32 tableNode = tablePlaceholder & ~KCDUtilityFlag; + +/* if (CommsDatSchema::IsGenericRecord(aElementId)) + { + // Not using dynamic_cast<>() here. RTTI is disabled (winscw). + // + // Presumably this works OK if the iRecordType is "null". + err = StorageL()->Create(tableNode, static_cast(iCurrentRecord)->iRecordType); + } + else + { + // and now create a node too, but without any attributes and without a table name + // because don't know what these should be as just storing first record or column +*/ err = StorageL()->Create(tableNode, aTableName); +// } + + if (err != KErrNone) + { + // unexpected error that should be logged and passed back to caller + __FLOG_STATIC3(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::CreatePlaceholderL() creating Node for id <%08x>, prepared id <%08x> CRepository::Create() returned %d"), aElementId, tableNode & ~KCDUtilityFlag, err); + } + } + } + } + CleanupStack::PopAndDestroy(&ids); + + if (aNodeTypeMask != KCDMaskShowRecordType) + { + // create the other node types as required + + switch(aNodeTypeMask) + { + case KCDMaskShowRecordId : + { + id = (aElementId & (KCDMaskShowRecordId | KCDMaskShowRecordType)) | (KCDNewRecordRequest & KCDMaskHideRes) | KCDUtilityFlag; + break; + } + case KCDMaskShowFieldType : + { + id = (aElementId & (KCDMaskShowFieldType | KCDMaskShowRecordType)) | (KCDNewColumnRequest & KCDMaskHideRes) | KCDUtilityFlag; + break; + } + }; + + err = StorageL()->Create(id, MEANINGLESS_NUMBER); + + if (err != KErrNone) + { + __FLOG_STATIC3(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::CreatePlaceholderL() for id <%08x> CRepository::Create() used id <%08x> and returned %d"), aElementId, id, err); + } + } + } + +void CMDBSessionImpl::CreatePlaceholderL(TMDBElementId& aElementId, TMDBElementId aNodeTypeMask, CMDBElement& aElement) +/* +Create placeholdertype info node which must never have any attributes set + + Table <0> Int + Record <0> Int + Column <0> Int +*/ + { + TInt err(KErrNone); + // always might need to create a table placeholder - create one if client is storing + // first record or column in a table as well as explicitly creating the table + TUint32 id = (aElementId & KCDMaskShowRecordType) | (KCDNewTableRequest & ~KCDChangedFlag) | KCDUtilityFlag ; + + RArrayids; + CleanupClosePushL(ids); + + TUint32 tablePlaceholder = id | KCDMaskShowFieldType | KCDMaskShowRecordId | KCDUtilityFlag; + if (KErrNotFound == StorageL()->FindL(tablePlaceholder, KCDCenRepNoMask, ids)) + { + err = StorageL()->Create(tablePlaceholder, MEANINGLESS_NUMBER); + if (err != KErrNone) + { + __FLOG_STATIC3(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::CreatePlaceholderL() for id <%08x>, prepared id <%08x> CRepository::Create() for missing table returned %d"), aElementId, tablePlaceholder, err); + } + else + { + if (aNodeTypeMask != KCDMaskShowRecordType) + { + TUint32 tableNode = tablePlaceholder & ~KCDUtilityFlag; + + if (CommsDatSchema::IsGenericRecord(aElementId)) + { + // Not using dynamic_cast<>() here. RTTI is disabled (winscw). + // + // Presumably this works OK if the iRecordType is "null". + err = StorageL()->Create(tableNode, static_cast(&aElement)->iRecordType); + } + else + { + // and now create a node too, but without any attributes and without a table name + // because don't know what these should be as just storing first record or column + err = StorageL()->Create(tableNode, KNullDesC); + } + + if (err != KErrNone) + { + // unexpected error that should be logged and passed back to caller + __FLOG_STATIC3(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::CreatePlaceholderL() creating Node for id <%08x>, prepared id <%08x> CRepository::Create() returned %d"), aElementId, tableNode & ~KCDUtilityFlag, err); + } + } + } + } + CleanupStack::PopAndDestroy(&ids); + + if (aNodeTypeMask != KCDMaskShowRecordType) + { + // create the other node types as required + + switch(aNodeTypeMask) + { + case KCDMaskShowRecordId : + { + id = (aElementId & (KCDMaskShowRecordId | KCDMaskShowRecordType)) | (KCDNewRecordRequest & KCDMaskHideRes) | KCDUtilityFlag; + break; + } + case KCDMaskShowFieldType : + { + id = (aElementId & (KCDMaskShowFieldType | KCDMaskShowRecordType)) | (KCDNewColumnRequest & KCDMaskHideRes) | KCDUtilityFlag; + break; + } + }; + + err = StorageL()->Create(id, MEANINGLESS_NUMBER); + + if (err != KErrNone) + { + __FLOG_STATIC3(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::CreatePlaceholderL() for id <%08x> CRepository::Create() used id <%08x> and returned %d"), aElementId, id, err); + } + } + } + + +void CMDBSessionImpl::CreateNodeL(TMDBElementId& aElementId, TMDBElementId aNodeTypeMask, CMDBElement& aElement, SGenericRecordTypeInfo* aFieldTypeInfo) +/* +Create a new node that shows the appropriate attributes and stores type information +given in the element passed in to the function + Table <0> Text + Record <0> Int + Column <0> Bin +*/ + { + TInt err(KErrNone); + TUint32 id = aElementId; + switch(aNodeTypeMask) + { + case KCDMaskShowRecordType : + { + CMDBTextFieldBase& ref = static_cast(aElement); + id = (aElementId & (KCDMaskShowRecordType | iWriteAttributeMask)) | KCDNewTableRequest; + __FLOG_STATIC2(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::CreateNodeL() for id <%08x> prepared id is <%08x>"), aElementId, id); + if (aElement.IsNull()) + { + TPtrC nothing(_L("_")); + err = StorageL()->Create(id, nothing); + } + else + err = StorageL()->Create(id, (TDesC&)ref); + break; + } + case KCDMaskShowRecordId : + { + id = (aElementId & (KCDMaskShowRecordId | KCDMaskShowRecordType | (~iWriteAttributeMask & KCDMaskShowAttributes))); + id |= (KCDNewRecordRequest & KCDMaskShowFieldType); + __FLOG_STATIC2(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::CreateNodeL() for id <%08x> prepared id is <%08x>"), aElementId, id); + err = StorageL()->Create(id, MEANINGLESS_NUMBER); + break; + } + case KCDMaskShowFieldType : + { + // CMDBBinFieldBase& ref = static_cast(aElement); + id = (aElementId & (KCDMaskShowFieldType | KCDMaskShowRecordType | iWriteAttributeMask)) | (KCDNewColumnRequest & KCDMaskShowRecordId); + __FLOG_STATIC2(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::CreateNodeL() for id <%08x> prepared id is <%08x>"), aElementId, id); + if (aFieldTypeInfo) + { + // Serialize to a binary "stream" the field info. + TPckg serializedTypeInfo(*aFieldTypeInfo); + err = StorageL()->Create(id, serializedTypeInfo); + } + break; + } + }; + + + if (err != KErrNone) + { + __FLOG_STATIC3(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::CreateNodeL() for id %08x, prepared id %08x CRepository::Create() returned %d"), aElementId, id, err); + } + + } + + + +void CMDBSessionImpl::MaybeCreateNodeL(CMDBElement& aElement) +/* +Check to see if a new node needs to be created and if so, create it. +Never allows creation of deprecated record types + +else lookup attributes + +Will leave with + KErrAlreadyExists if requested node already exists. + KErrOverflow if no space to store a new node + KErrNotSupported if client asks to create deprecated record (will only get here + if mapping turned off because current version of session chosen by client) +@internalComponent +*/ + { + TMDBElementId elementId = aElement.ElementId(); + + // Checking for nodes the user has asked to be created + + if ( (elementId & KCDMaskHideAttrAndRes) == KCDNewTableRequest ) + { + //Not supported at the moment + } + else + { + TInt err(KErrNotFound); + TPtrC tableName(KNullDesC); + + if (CommsDatSchema::IsNode(elementId)) + { + if (CommsDatSchema::IsDeprecatedRecord( +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + elementId +#endif //SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + )) + { + // Client is using a deprecated record in the 'latest' session + __FLOG_STATIC1(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::MaybeCreateNode() this client has chosen not to use an old data schema version, but is accessing a deprecated node <%08x>"), aElement.ElementId()); + ASSERT(KErrNotSupported); + User::Leave(KErrNotSupported); + } + +/* if (CommsDatSchema::IsGenericRecord(elementId) ) + { + CMDBGenericRecord* genRec = static_cast(&aElement); + if (NULL != genRec->iRecordType.Ptr()) + { + __FLOG_STATIC0(KLogComponent, KCDInfoLog,_L("janos: genRec.iRecordType is not NULL")); + tableName.Set(genRec->iRecordType); + } + }*/ + + // check if the node exists and find out the attributes the element should have + err = LoadNodeAttributesL(elementId); + } + else + { + // First check if the node exists and find out the attributes the element should have + err = LoadElementAttributesL(elementId); + } + + // Don't need to do anything more if element already exists + // or if element is a field + if (err == KErrNotFound) + { + WriteAllowedL(elementId); + + if ( CommsDatSchema::IsNewRecordRequest(elementId) ) + { + // assign new record id and create node + SetNodeIdL(elementId, KCDUtilityFlag | KCDMaskShowType, KCDInitialRecordId, KCDMaxRecordId, KCDMaxRecords); + elementId &= ~KCDUtilityFlag; +// CreatePlaceholderL(elementId, KCDMaskShowRecordId, tableName); + CreatePlaceholderL(elementId, KCDMaskShowRecordId, aElement); + CreateNodeL(elementId, KCDMaskShowRecordId, aElement); + } + else if ( CommsDatSchema::IsNewColumnRequest(elementId) ) + { + elementId &= ~KCDUtilityFlag; + // assign new column id and create node + SetNodeIdL(elementId, KCDMaskShowFieldType, KCDInitialColumnId, KCDMaxColumnId, KCDMaxColumns); +// CreatePlaceholderL(elementId, KCDMaskShowFieldType, tableName); + CreatePlaceholderL(elementId, KCDMaskShowFieldType, aElement); + CreateNodeL(elementId, KCDMaskShowFieldType, aElement); + } + else if ( (elementId & KCDMaskShowRecordType) != 0 ) + { + // Is an element where the id has already been set by caller + if ( CommsDatSchema::IsRecord(elementId) ) + { + // create new record +// CreatePlaceholderL(elementId, KCDMaskShowRecordId, tableName); + CreatePlaceholderL(elementId, KCDMaskShowRecordId, aElement); + if ( CommsDatSchema::IsTemplate(elementId) ) + { + // Template records must be hidden + elementId |= ECDHidden; + } + CreateNodeL(elementId, KCDMaskShowRecordId, aElement); + } + // columns shouldn't be set by user.explicitly - new column request should be used + // other entries would be individual fields and wouldn't get here because + // LoadElementAttributes would have returned KErrNone. + } + else + { + // user has set an invalid id + __FLOG_STATIC1(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::MaybeCreateNode() Element <%08x> is not a valid element id"), aElement.ElementId()); + User::Leave(KErrNotFound); + } + } + } + //pass back new node id or set of appropriate attributes + aElement.SetElementId(elementId); + } + + + +TInt CMDBSessionImpl::MaybeModifyNodeL(TMDBElementId& aElementId) +/* +*/ + { + TBool retval(0); + if (! iInModification) + { + TMDBElementId storedId(aElementId & KCDMaskHideRes); + TMDBElementId mask = ~(KCDMaskShowAttributes | KCDChangedFlag); + + TInt err = LoadElementAttributesL(storedId); + + if ( err == KErrNotFound && + ( ( (storedId & KCDMaskShowFieldType) != KCDMaskShowFieldType ) || + ( (storedId & KCDMaskShowRecordId) != KCDMaskShowRecordId ) ) ) + { + err = KErrNone; + } + + if ( (aElementId & KCDMaskShowAttributes) != (storedId & KCDMaskShowAttributes) ) + { + // this means the element was found but didn't have these attributes. + // So need to move it and all linked elements. + + TUint32 partialSourceId(storedId); + TUint32 partialTargetId(aElementId); + TUint32 targetAttributes = (aElementId ^ storedId) & KCDMaskShowAttributes; + + if ( CommsDatSchema::IsTable(aElementId) ) + { + // move all records, columns and fields in this table + mask = KCDMaskShowRecordType | targetAttributes; + partialSourceId &= (KCDMaskShowRecordType | KCDMaskShowAttributes); + partialTargetId &= (KCDMaskShowRecordType | KCDMaskShowAttributes); + } + else if ( CommsDatSchema::IsRecord(aElementId) ) + { + // move all fields in this record + mask = KCDMaskShowRecordType | KCDMaskShowRecordId | targetAttributes; + partialSourceId &= (KCDMaskShowRecordType | KCDMaskShowRecordId | KCDMaskShowAttributes); + partialTargetId &= (KCDMaskShowRecordType | KCDMaskShowRecordId | KCDMaskShowAttributes); + } + else if ( CommsDatSchema::IsColumn(aElementId) ) + { + // move all fields in this column + mask = KCDMaskShowRecordType | KCDMaskShowFieldType | targetAttributes; + partialSourceId &= (KCDMaskShowRecordType | KCDMaskShowFieldType | KCDMaskShowAttributes); + partialTargetId &= (KCDMaskShowRecordType | KCDMaskShowFieldType | KCDMaskShowAttributes); + } + else + { + // this element is not a node, but a field and yet was not found with expected set of attributes. + // Can't change attributes of single fields so in error situation. + __FLOG_STATIC1(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::MaybeModifyNodeL() for id <%08x> being asked to change attributes on single field which is an error"), partialSourceId ); + User::Leave(KErrNotFound); + } + + __FLOG_STATIC3(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::MaybeModifyNodeL() About to call CRepository::MoveL() to move everything at id %08x to %08x using the mask %08x."), partialSourceId, partialTargetId, mask); + + TUint32 errorId(0); + err = StorageL()->Move(partialSourceId, partialTargetId, mask, errorId); + + if (err != KErrNone) + { + __FLOG_STATIC5(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::MaybeModifyNodeL() for id %08x, moving to <%08x> with the mask <%08x>. CRepository::MoveL() returned %d and failed at <%08x>"), partialSourceId, partialTargetId, mask, retval, errorId); + } + else + { + iInModification = ETrue; + retval = ETrue; + } + } + } + + return retval; + } + + +TBool CompareInstance(const TUint32& aFirst, const TUint32& aSecond) + { + return( (aFirst & KCDMaskShowRecordId) == (aSecond & KCDMaskShowRecordId)); + } + + +TInt CMDBSessionImpl::MaybeDeleteNodeL(CMDBElement* /* aElement */, TMDBElementId& aElementId) + { + TMDBElementId id(aElementId); + + // check element id exists + TInt err = LoadElementAttributesL(id); + + if (err == KErrNone) + { + RArray ids; + CleanupClosePushL(ids); + + // set mask + TUint32 mask(KCDMaskHideRes); + TUint32 nodemask(KCDMaskHideRes); + + // if is table + if ( CommsDatSchema::IsTable(id) ) + { + mask = KCDMaskShowRecordType | KCDUtilityFlag; + nodemask = mask | KCDMaskShowFieldType | iWriteAttributeMask; // will find records and table. Not enough - need to do two finds + } + // if is record + else if ( CommsDatSchema::IsRecord(id) ) + { + mask = KCDMaskShowRecordType | KCDMaskShowRecordId | KCDUtilityFlag; + nodemask = mask | KCDMaskShowFieldType | iWriteAttributeMask; + } + // if is column + else if ( CommsDatSchema::IsColumn(id) ) + { + mask = KCDMaskShowRecordType | KCDMaskShowFieldType | KCDUtilityFlag; + nodemask = mask | KCDMaskShowRecordId | iWriteAttributeMask; + } + + // otherwise just delete single field with no mask + + __FLOG_STATIC2(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::MaybeDeleteNode() for id <%08x> CRepository::FindL using mask <%08x>"), aElementId, mask); + + + if ( mask != KCDMaskHideRes ) + { + RArray placeholders; + CleanupClosePushL(placeholders); + // find all relevant placeholders + err = StorageL()->FindL((aElementId & ~iWriteAttributeMask) | KCDUtilityFlag, mask, placeholders); + + if (placeholders.Count() > 0) + { + RArray nodes; + CleanupClosePushL(nodes); + + err = StorageL()->FindL(aElementId & ~iWriteAttributeMask, nodemask, nodes); + + if(CommsDatSchema::IsGenericRecord(aElementId)) + { + TUint32 checkid = KCDMaskShowRecordId; + TInt instanceid; + while((instanceid = nodes.Find(checkid,TIdentityRelation(CompareInstance))) != KErrNotFound) + { + nodes.Remove(instanceid); + } + while((instanceid = placeholders.Find(checkid,TIdentityRelation(CompareInstance))) != KErrNotFound) + { + placeholders.Remove(instanceid); + } + placeholders.Compress(); + nodes.Compress(); + } + + + if (nodes.Count() == placeholders.Count() ) + { + // delete the placeholders in a batch + for (TInt i = 0; i < placeholders.Count(); i++) + { + err = StorageL()->Delete(placeholders[i]); + if( err != KErrNone) + { + __FLOG_STATIC2(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::MaybeDeleteNode() failed to delete a placeholder <%08x> with error %d"), placeholders[i], err); + User::Leave(err); + } + } + + if(nodes.Count()) + { +#ifndef __TOOLS2__ + TBool modemBearerDeleted = ((nodes[0] & KCDMaskShowRecordType) == KCDTIdModemBearerRecord); + NotifierL()->MaybeNotifyChangeForDelete(nodes[0], modemBearerDeleted); +#endif + } + } + else + { + // place holders have no attributes, but nodes do. + // if cannot see same number of nodes and placeholders this indicates + // client may need extra capabilities to see or manipulate all nodes + __FLOG_STATIC1(KLogComponent, KCDErrLog, _L("CMDBSessionImpl::MaybeDeleteNode() client does not have permission to delete all elements in this node <%08x>"), aElementId); + User::Leave(KErrPermissionDenied); + } + + CleanupStack::PopAndDestroy(&nodes); + } + + CleanupStack::PopAndDestroy(&placeholders); + } + + // find all relevant items + err = StorageL()->FindL(aElementId & ~iWriteAttributeMask, mask, ids); + + if(CommsDatSchema::IsGenericRecord(aElementId)) + { + TUint32 checkid = KCDMaskShowRecordId; + TInt instanceid; + while((instanceid = ids.Find(checkid,TIdentityRelation(CompareInstance))) != KErrNotFound) + { + ids.Remove(instanceid); + } + ids.Compress(); + } + + + if (ids.Count() > 0) + { + __FLOG_STATIC3(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::MaybeDeleteNode() for id <%08x> CRepository::FindL() with mask <%08x> returned %d entries"), aElementId, mask, ids.Count()); + // delete everything in a batch + for (TInt i = 0; i < ids.Count(); i++) + { + err = StorageL()->Delete(ids[i]); +#ifndef __TOOLS2__ + NotifierL()->MaybeNotifyChangeForDelete(ids[i], 0); +#endif + } + // reset NotNull flag + aElementId &= ~KCDNotNullFlag; + } + else + { + __FLOG_STATIC3(KLogComponent, KCDInfoLog, _L("CMDBSessionImpl::MaybeDeleteNode() for id <%08x> CRepository::FindL() with mask <%08x> returned err %d"), aElementId, mask, err); + } + + CleanupStack::PopAndDestroy(&ids); + } + + return err; + } + + + + +TInt CMDBSessionImpl::FindMatchL(RArray& aCandidates, RArray& aMatches, TUint32 aIdMask) +/* +Utility function to match a CMDBElement with a list of possible candidates by id. + +@internalComponent +*/ + { + + TInt retval = KErrNotFound; + + //ignore template record + if ( aCandidates.Count() ) + { + if ( (aCandidates[0] & KCDMaskShowRecordId) == KCDDefaultRecord ) + { + aCandidates.Remove(0); + } + } + + if ( aCandidates.Count() && aMatches.Count()) + { + TInt count(aMatches.Count()); + while(count--) + { + if(KErrNotFound == aCandidates.Find(aMatches[count],TIdentityRelation(CompareInstance))) + { + aMatches.Remove(count); + } + } + aMatches.Compress(); + } + else if ( aCandidates.Count()) + { + for (TInt i = 0; i < aCandidates.Count(); i++) + { + retval = aMatches.Append(aCandidates[i] | aIdMask); + + if (retval != KErrNone) + { + aMatches.Close(); + if (retval == KErrNoMemory) + { + User::Leave(KErrNoMemory); + } + } + } + } + + if ( aMatches.Count() ) + { + retval = KErrNone; + } + + return retval; + + } + + + +//EOF