diff -r 000000000000 -r dab8a81a92de omads/omadsextensions/adapters/sms/src/ChangeFinder.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omads/omadsextensions/adapters/sms/src/ChangeFinder.cpp Mon Nov 23 14:46:41 2009 +0200 @@ -0,0 +1,697 @@ +/* +* Copyright (c) 2005-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: Part of SyncML Data Synchronization Plug In Adapter +* +*/ + + +#include "ChangeFinder.h" +#include "Logger.h" + +const TUint KSnapshotFormatVersion ( 0xf0000001 ); // format version + +// ----------------------------------------------------------------------------- +// CChangeFinder::NewL +// Static function to create CChangeFider object(s) +// ----------------------------------------------------------------------------- +CChangeFinder* CChangeFinder::NewL( MSmlSyncRelationship& aSyncRelationship, TKeyArrayFix aKey, + TBool& aHasHistory, TInt aStreamUid ) + { + CChangeFinder* self = new (ELeave) CChangeFinder( aSyncRelationship, aKey, aStreamUid ); + CleanupStack::PushL( self ); + self->ConstructL( aHasHistory ); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::CChangeFinder +// Constructor for the class +// ----------------------------------------------------------------------------- +CChangeFinder::CChangeFinder( MSmlSyncRelationship& aSyncRelationship, TKeyArrayFix aKey, TInt aStreamUid ) : +iSyncRelationship( aSyncRelationship ), +iKey( aKey ), +iStreamUid( aStreamUid ), +iDataStoreUid( KErrNotFound ) + { + + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::~CChangeFinder +// Destructor for the class, closes the ChangeFinder and writes snapshot to stream +// ----------------------------------------------------------------------------- +CChangeFinder::~CChangeFinder() + { + LOGGER_ENTERFN( "CChangeFinder::~CChangeFinder" ); + TInt error; + TRAP( error, CloseL() ); + if ( error != KErrNone ) + { + LOGGER_WRITE( "CChangeFinder::~CChangeFinder, CloseL failed." ); + } + + delete iCurrentSnapshot; + delete iOldSnapshot; + + LOGGER_LEAVEFN( "CChangeFinder::~CChangeFinder" ); + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::ConstructL +// 2nd phase constructor for the class, reads snapshot from stream +// ----------------------------------------------------------------------------- +void CChangeFinder::ConstructL( TBool& aHasHistory ) + { + LOGGER_ENTERFN( "CChangeFinder::ConstructL" ); + + aHasHistory = EFalse; + RReadStream readStream; + + TUid streamId; + streamId.iUid = iStreamUid; + + aHasHistory = iSyncRelationship.IsStreamPresentL(streamId); + + if (aHasHistory) + { + iSyncRelationship.OpenReadStreamLC(readStream, streamId); + + // Read the index, first create snapshot array + iOldSnapshot = new (ELeave) CSnapshotArray( KSnapshotGranularity ); + + // Read used format version + TUint formatVer = readStream.ReadUint32L(); + if ( formatVer != KSnapshotFormatVersion ) + { + // Wrong version, do not try to import data + LOGGER_WRITE("CChangeFinder::ConstructL, Wrong format version -> no history"); + aHasHistory = EFalse; + CleanupStack::PopAndDestroy(); // readStream + LOGGER_LEAVEFN("CChangeFinder::ConstructL"); + return; + } + + // Read item count + TInt count = readStream.ReadUint32L(); + + // Read items + for ( TInt i=0; iInsertIsqL( item, iKey ); + } + + readStream.Close(); + readStream.Pop(); + } + else + { + LOGGER_WRITE("CChangeFinder::ConstructL, no sync history."); + } + + LOGGER_LEAVEFN("CChangeFinder::ConstructL"); + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::CloseL +// Closes ChangeFinder object and writes snapshot to stream +// ----------------------------------------------------------------------------- +void CChangeFinder::CloseL() + { + LOGGER_ENTERFN( "CChangeFinder::CloseL" ); + + // Write to stream + RWriteStream writeStream; + + TUid streamId; + streamId.iUid = iStreamUid; + + // Open write stream + iSyncRelationship.OpenWriteStreamLC( writeStream, streamId ); + + // Write used format version + writeStream.WriteUint32L( KSnapshotFormatVersion ); + + // Write item count + TInt count(0); + if ( iOldSnapshot ) + { + count = iOldSnapshot->Count(); + } + writeStream.WriteUint32L(count); + + // Write items + for (TInt i=0; iAt( i ); + item.ExternalizeL( writeStream ); + } + + writeStream.CommitL(); + writeStream.Close(); + writeStream.Pop(); + + LOGGER_LEAVEFN( "CChangeFinder::CloseL" ); + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::ResetL +// Resets synchronization history, all contetn is considered new after this call +// ----------------------------------------------------------------------------- +void CChangeFinder::ResetL() + { + LOGGER_ENTERFN( "CChangeFinder::ResetL" ); + // Delete old change information + if ( iOldSnapshot ) + { + LOGGER_WRITE("iOldSnapshot->Reset()"); + iOldSnapshot->Reset(); + } + + // Write 'null' data to file, + // this removes change history from the file + CloseL(); + + LOGGER_LEAVEFN( "CChangeFinder::ResetL" ); + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::FindChangedItemsL +// Compares snapshots, finds changed items +// ----------------------------------------------------------------------------- +void CChangeFinder::FindChangedItemsL( CNSmlDataItemUidSet& aChangedUids ) + { + LOGGER_ENTERFN( "CChangeFinder::FindChangedItemsL" ); + + if ( !iCurrentSnapshot ) + { + LOGGER_WRITE( "CChangeFinder::FindChangedItemsL leaved, no current snapshot." ); + User::Leave( KErrNotFound ); + } + + if ( !iOldSnapshot ) + { + LOGGER_WRITE( "CChangeFinder::FindChangedItemsL leaved, no old snapshot." ); + User::Leave( KErrNotFound ); + } + + TInt index; + TInt count = iCurrentSnapshot->Count(); + for ( TInt i=0; i < count; i++ ) + { + const TSnapshotItem& currentItem = iCurrentSnapshot->At( i ); + // Find this entry from the old snapshot + if ( iOldSnapshot->FindIsq( currentItem, iKey, index ) == KErrNone) + { + // This is the old item + TSnapshotItem& oldItem = iOldSnapshot->At( index ); + // Compare times to see whether this was changed or item was read + if ( ( oldItem.LastChangedDate() != currentItem.LastChangedDate() ) + || ( oldItem.Unread() && !currentItem.Unread() ) + || ( !oldItem.Unread() && currentItem.Unread() ) + || ( oldItem.FolderName().Compare( currentItem.FolderName() ) != 0 ) ) + { + aChangedUids.AddItem( currentItem.ItemId() ); + LOGGER_WRITE_1( "Item %d was changed.", currentItem.ItemId() ); + } + } + } + + LOGGER_LEAVEFN( "CChangeFinder::FindChangedItemsL" ); + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::FindDeletedItemsL +// Compares snapshots, finds deleted items +// ----------------------------------------------------------------------------- +void CChangeFinder::FindDeletedItemsL( CNSmlDataItemUidSet& aDeletedUids ) + { + LOGGER_ENTERFN( "CChangeFinder::FindDeletedItemsL" ); + + if ( !iOldSnapshot ) + { + LOGGER_LEAVEFN( "CChangeFinder::FindDeletedItemsL leaved, no old snapshot." ); + User::Leave( KErrNotFound ); + } + + TInt index; + TInt count = iOldSnapshot->Count(); + for ( TInt i=0; i < count; i++ ) + { + const TSnapshotItem& currentItem = iOldSnapshot->At( i ); + + // If there's no current snapshot, this definately is deleted item + if ( !iCurrentSnapshot ) + { + aDeletedUids.AddItem( currentItem.ItemId() ); + LOGGER_WRITE_1( "Item %d was deleted.", currentItem.ItemId() ); + } + // It is also new if it doesn't exist int the current snapshot. + else if ( iCurrentSnapshot->FindIsq( currentItem, iKey, index ) != KErrNone ) + { + aDeletedUids.AddItem( currentItem.ItemId() ); + LOGGER_WRITE_1( "Item %d was deleted.", currentItem.ItemId() ); + } + } + + LOGGER_LEAVEFN( "CChangeFinder::FindDeletedItemsL" ); + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::FindNewItemsL +// Compares snapshots, finds new items +// ----------------------------------------------------------------------------- +void CChangeFinder::FindNewItemsL( CNSmlDataItemUidSet& aNewUids ) + { + LOGGER_ENTERFN( "CChangeFinder::FindNewItemsL" ); + + if ( !iCurrentSnapshot ) + { + LOGGER_WRITE( "CChangeFinder::FindNewItemsL leaved, no current snapshot." ); + User::Leave( KErrNotFound ); + } + + TInt index; + TInt count = iCurrentSnapshot->Count(); + for ( TInt i=0; i < count; i++ ) + { + const TSnapshotItem& currentItem = iCurrentSnapshot->At( i ); + + // If there's no old snapshot, all items are new + if ( !iOldSnapshot ) + { + aNewUids.AddItem( currentItem.ItemId() ); + LOGGER_WRITE_1( "Item %d was new.", currentItem.ItemId() ); + } + // It is also new if it doesn't exist int the old snapshot. + else if ( iOldSnapshot->FindIsq( currentItem, iKey, index ) != KErrNone ) + { + aNewUids.AddItem( currentItem.ItemId() ); + LOGGER_WRITE_1( "Item %d was new.", currentItem.ItemId() ); + } + } + + LOGGER_LEAVEFN( "CChangeFinder::FindNewItemsL" ); + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::FindMovedItemsL +// Compares snapshots, finds moved items +// ----------------------------------------------------------------------------- +void CChangeFinder::FindMovedItemsL( CNSmlDataItemUidSet& aMovedUids ) + { + LOGGER_ENTERFN( "CChangeFinder::FindMovedItemsL" ); + + if ( !iCurrentSnapshot ) + { + LOGGER_WRITE( "CChangeFinder::FindMovedItemsL leaved, no current snapshot." ); + User::Leave( KErrNotFound ); + } + + if ( !iOldSnapshot ) + { + LOGGER_WRITE( "CChangeFinder::FindMovedItemsL leaved, no old snapshot." ); + User::Leave( KErrNotFound ); + } + + TInt index; + TInt count = iCurrentSnapshot->Count(); + for ( TInt i=0; i < count; i++ ) + { + const TSnapshotItem& currentItem = iCurrentSnapshot->At( i ); + + // Find this entry from the old snapshot + if(iOldSnapshot->FindIsq( currentItem, iKey, index ) == KErrNone) + { + // This is the old item + TSnapshotItem& oldItem = iOldSnapshot->At( index ); + + // Report only moved items in which only parent id has been changed + if ( oldItem.ParentId() != currentItem.ParentId() + && oldItem.LastChangedDate() == currentItem.LastChangedDate() + && !(oldItem.Unread() && !currentItem.Unread() ) + && !(!oldItem.Unread() && currentItem.Unread() ) ) + { + aMovedUids.AddItem( currentItem.ItemId() ); + LOGGER_WRITE_1( "Item %d was moved.", currentItem.ItemId() ); + } + } + } + + LOGGER_LEAVEFN( "CChangeFinder::FindMovedItemsL" ); + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::ItemAddedL +// Adds item to snapshot, this item is no longer considered new +// ----------------------------------------------------------------------------- +void CChangeFinder::ItemAddedL( const TSnapshotItem& aItem ) + { + LOGGER_ENTERFN( "CChangeFinder::ItemAddedL" ); + + // Add this to old snapshot, if there's no old snapshot it must be created + if ( !iOldSnapshot ) + { + iOldSnapshot = new (ELeave) CSnapshotArray( KSnapshotGranularity ); + } + + LOGGER_WRITE_1( "Adding item %d.", aItem.ItemId() ); + + TRAPD( error, iOldSnapshot->InsertIsqL( aItem, iKey ) ); + if ( error == KErrAlreadyExists ) + { + // It was already committed, no actions required + LOGGER_WRITE( "iOldSnapshot->InsertIsqL leaved with KErrAlreadyExists" ); + } + else if ( error != KErrNone ) + { + LOGGER_WRITE_1( "iOldSnapshot->InsertIsqL leaved with %d.", error ); + User::Leave( error ); + } + + LOGGER_LEAVEFN( "CChangeFinder::ItemAddedL" ); + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::ItemDeletedL +// Removes item to snapshot, this item is no longer considered deleted +// ----------------------------------------------------------------------------- +void CChangeFinder::ItemDeletedL( const TSnapshotItem& aItem ) + { + LOGGER_ENTERFN( "CChangeFinder::ItemDeleted" ); + + LOGGER_WRITE_1( "deleting item %d.", aItem.ItemId() ); + + if ( !iOldSnapshot ) + { + LOGGER_WRITE( "CChangeFinder::ItemDeleted leaved, no old snapshot." ); + User::Leave( KErrNotFound ); + } + + // Delete item from the old snapshot + TInt index; + if ( iOldSnapshot->FindIsq( aItem, iKey, index ) == KErrNone ) + { + iOldSnapshot->Delete( index ); + } + else // Skip, there wasn't such entry + { + LOGGER_WRITE( "iOldSnapshot->FindIsq, item was not found." ); + } + + LOGGER_LEAVEFN( "CChangeFinder::ItemDeleted" ); + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::ItemUpdatedL +// Updates item to snapshot, this item is no longer considered changed +// ----------------------------------------------------------------------------- +void CChangeFinder::ItemUpdatedL( const TSnapshotItem& aItem ) + { + LOGGER_ENTERFN( "CChangeFinder::ItemUpdatedL" ); + + LOGGER_WRITE_1( "Updating item %d.", aItem.ItemId() ); + + // There must be such entry in the snapshot after this + // If there isn't old snapshot, we'll create it and add the item + if ( !iOldSnapshot ) + { + iOldSnapshot = new (ELeave) CSnapshotArray( KSnapshotGranularity ); + ItemAddedL( aItem ); + } + else + { + // Update item in the old snapshot + TInt index; + if ( iOldSnapshot->FindIsq( aItem, iKey, index ) == KErrNone ) + { + TSnapshotItem& oldItem = iOldSnapshot->At( index ); + oldItem = aItem; + } + else + { + // There was old snapshot but no such item. Let's add it + ItemAddedL( aItem ); + } + + } + + LOGGER_LEAVEFN( "CChangeFinder::ItemUpdatedL" ); + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::ItemMovedL +// Moves item within snapshot, this item is no longer considered moved +// ----------------------------------------------------------------------------- +void CChangeFinder::ItemMovedL( const TSnapshotItem& aItem ) + { + LOGGER_ENTERFN( "CChangeFinder::ItemMovedL" ); + + LOGGER_WRITE_1( "Moving item %d.", aItem.ItemId() ); + + // There must be such entry in the snapshot after this + // If there isn't old snapshot, we'll create it and add the item + if ( !iOldSnapshot ) + { + iOldSnapshot = new (ELeave) CSnapshotArray( KSnapshotGranularity ); + ItemAddedL( aItem ); + } + else + { + // Update item's parent in the old snapshot + TInt index; + if ( iOldSnapshot->FindIsq( aItem, iKey, index ) == KErrNone ) + { + TSnapshotItem& oldItem = iOldSnapshot->At( index ); + oldItem.SetParentId( aItem.ParentId() ); + } + else + { + // There was old snapshot but no such item. Let's add it + ItemAddedL( aItem ); + } + } + + LOGGER_LEAVEFN("CChangeFinder::ItemMovedL"); + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::CommitChangesL +// Commits current changes to snapshot +// ----------------------------------------------------------------------------- +void CChangeFinder::CommitChangesL() + { + LOGGER_ENTERFN( "CChangeFinder::CommitChangesL" ); + + if ( !iCurrentSnapshot ) + { + LOGGER_WRITE( "CChangeFinder::CommitChangesL leaved, current snapshot missing." ); + User::Leave( KErrNotFound ); + } + + if ( !iOldSnapshot ) + { + iOldSnapshot = new (ELeave) CSnapshotArray( KSnapshotGranularity ); + } + + // Delete everything from the old snapshot + iOldSnapshot->Reset(); + + // Loop through all the items in current snapshot + TInt count = iCurrentSnapshot->Count(); + + // Copy everything from current to old snapshot + for ( TInt i=0; i < count; i++ ) + { + const TSnapshotItem& newItem = iCurrentSnapshot->At( i ); + + // Commit it to the old array. + TRAPD( error, iOldSnapshot->InsertIsqL( newItem, iKey ) ); + if ( error == KErrAlreadyExists ) + { + // It was already committed, this is an internal error of change finder + LOGGER_WRITE( "iOldSnapshot->InsertIsqL leaved with KErrAlreadyExists." ); + User::Leave( error ); + } + else if ( error != KErrNone ) + { + LOGGER_WRITE_1( "iOldSnapshot->InsertIsqL leaved with %d.", error ); + User::Leave( error ); + } + } + LOGGER_LEAVEFN( "CChangeFinder::CommitChangesL" ); + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::CommitChangesL +// Commits current changes to snapshot, affects only a specified group of items +// ----------------------------------------------------------------------------- +void CChangeFinder::CommitChangesL( const MSmlDataItemUidSet& aUids ) + { + LOGGER_ENTERFN( "CChangeFinder::CommitChangesL" ); + + // This function commits changes from current snapshot to old snapshot + // But commits only the entries in the parameter array + if ( !iCurrentSnapshot ) + { + LOGGER_WRITE( "CChangeFinder::CommitChangesL leaved, current snapshot missing." ); + User::Leave( KErrNotFound ); + } + + if ( !iOldSnapshot ) + { + iOldSnapshot = new (ELeave) CSnapshotArray( KSnapshotGranularity ); + } + + // Use only these uid values + TInt index; + TInt count = aUids.ItemCount(); + + for ( TInt i=0; i < count; i++ ) + { + TSmlDbItemUid uid = aUids.ItemAt( i ); + TSnapshotItem item( uid ); + // Let's see if this uid exists in the current snapshot + if ( iCurrentSnapshot->FindIsq( item, iKey, index ) == KErrNone ) + { + // This is the new item + const TSnapshotItem& newItem = iCurrentSnapshot->At( index ); + + // Let's see if we can find the old one + if ( iOldSnapshot->FindIsq( item, iKey, index ) == KErrNone ) + { + // This is the old item + TSnapshotItem& oldItem = iOldSnapshot->At( index ); + + // Copy new item over the old one, this'll commit the change + oldItem = newItem; + } + else // This entry was not found. It means that it is new one + { + // Commit it to the old array. + ItemAddedL( newItem ); + } + } + else + { + // This item was deleted from the current snapshot. + TSnapshotItem toDelete( item ); + ItemDeletedL( toDelete ); + } + } + + LOGGER_LEAVEFN( "CChangeFinder::CommitChangesL" ); + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::SetNewSnapshot +// Sets new snapshot (to be compared against), ChangeFinder takes ownership +// ----------------------------------------------------------------------------- +void CChangeFinder::SetNewSnapshot( CSnapshotArray* aNewSnapshot ) + { + LOGGER_ENTERFN( "CChangeFinder::SetNewSnapshot" ); + + // Delete existing snapshot + delete iCurrentSnapshot; + + // Set submitted snapshot as active + iCurrentSnapshot = aNewSnapshot; + LOGGER_LEAVEFN( "CChangeFinder::SetNewSnapshot" ); + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::DataStoreUid +// returns stored data store id number +// ----------------------------------------------------------------------------- +TInt64 CChangeFinder::DataStoreUid() const + { + LOGGER_ENTERFN( "CChangeFinder::DataStoreUid" ); + LOGGER_LEAVEFN( "CChangeFinder::DataStoreUid" ); + return iDataStoreUid; + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::SetDataStoreUid +// Sets data store id number +// ----------------------------------------------------------------------------- +void CChangeFinder::SetDataStoreUid( TInt64 aUid ) + { + LOGGER_ENTERFN( "CChangeFinder::SetDataStoreUid" ); + iDataStoreUid = aUid; + LOGGER_LEAVEFN( "CChangeFinder::SetDataStoreUid" ); + } + +// ----------------------------------------------------------------------------- +// CChangeFinder::UpdatePartialL +// Returns ETrue if item can be updated partially (only status bits are changed) +// ----------------------------------------------------------------------------- +TBool CChangeFinder::UpdatePartialL( TSmlDbItemUid& aUid ) + { + LOGGER_ENTERFN( "CChangeFinder::UpdatePartialL" ); + + if ( !iCurrentSnapshot ) + { + LOGGER_WRITE( "CChangeFinder::UpdatePartialL leaved, current snapshot missing." ); + User::Leave( KErrNotFound ); + } + + if ( !iOldSnapshot ) + { + LOGGER_LEAVEFN( "CChangeFinder::UpdatePartialL" ); + return EFalse; + } + + TInt index; + TSnapshotItem item( aUid ); + // Find from current snapshot, if not found -> deleted + if ( iCurrentSnapshot->FindIsq( item, iKey, index ) != KErrNone ) + { + LOGGER_LEAVEFN( "CChangeFinder::UpdatePartialL" ); + return EFalse; + } + + // Current item + const TSnapshotItem& currentItem = iCurrentSnapshot->At( index ); + + // Old item, if not found -> added + if ( iOldSnapshot->FindIsq( item, iKey, index ) != KErrNone ) + { + LOGGER_LEAVEFN( "CChangeFinder::UpdatePartialL" ); + return EFalse; + } + else + { + // This is the old item + TSnapshotItem& oldItem = iOldSnapshot->At( index ); + + // Status bits must have been changed to allow partial update + if ( oldItem.Unread() == currentItem.Unread() ) + { + LOGGER_LEAVEFN( "CChangeFinder::UpdatePartialL" ); + return EFalse; + } + + // Date should be same, otherwise 'just' changed item + if ( oldItem.LastChangedDate() == currentItem.LastChangedDate() ) + { + LOGGER_LEAVEFN( "CChangeFinder::UpdatePartialL" ); + return ETrue; + } + + LOGGER_LEAVEFN( "CChangeFinder::UpdatePartialL" ); + return EFalse; + } + }