diff -r f5050f1da672 -r 04becd199f91 javaextensions/location/landmarks/src/clapilandmarkstore.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaextensions/location/landmarks/src/clapilandmarkstore.cpp Tue Apr 27 16:30:29 2010 +0300 @@ -0,0 +1,505 @@ +/* +* Copyright (c) 2008 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: Implements native landmark store functionality + * +*/ + + +// INTERNAL INCLUDES +#include "clapilandmarkstore.h" +#include "mlapicategorymanager.h" +#include "mlapilmdatabaseeventnotifier.h" +#include "clapilandmarksearchfactory.h" +#include "clapilandmark.h" +#include "tlapisearchcriteria.h" +#include "cleanupresetanddestroy.h" +#include "lapipanics.h" +#include "logger.h" + +// EXTERNAL INCLUDES +#include +#include +#include + +// UNNAMED LOCAL NAMESPACE +namespace +{ +// Minimum usage of the native landmark database. If the usage drops +// below this level, the database will be compacted to avoid that the +// Landmark Server would do that which eventually locks the database +const TReal KLAPIMinCompactUsage = 0.7; +} + +// --------------------------------------------------------------------------- +// CLAPILandmarkStore::CLAPILandmarkStore +// --------------------------------------------------------------------------- +// +CLAPILandmarkStore::~CLAPILandmarkStore() +{ + JELOG2(EJavaLocation); + // Closes the database and releases all resources + Close(); + delete iStoreUri; +} + +// --------------------------------------------------------------------------- +// CLAPILandmarkStore::ConstructL +// (other items were commented in a header +// --------------------------------------------------------------------------- +// +void CLAPILandmarkStore::ConstructL() +{ + JELOG2(EJavaLocation); + // Get the name of the landmark store + iStoreUri = iLandmarkDatabase->DatabaseUriLC(); + CleanupStack::Pop(iStoreUri); + // Create landmark search factory for filtering landmarks + iSearchFactory = CLAPILandmarkSearchFactory::NewL(*iLandmarkDatabase); +} + +// --------------------------------------------------------------------------- +// CLAPILandmarkStore::NewL +// --------------------------------------------------------------------------- +// +CLAPILandmarkStore* CLAPILandmarkStore::NewL(const TCtorParams& aParams) +{ + JELOG2(EJavaLocation); + CLAPILandmarkStore* self = CLAPILandmarkStore::NewLC(aParams); + CleanupStack::Pop(self); + return self; +} + +// --------------------------------------------------------------------------- +// CLAPILandmarkStore::NewLC +// --------------------------------------------------------------------------- +// +CLAPILandmarkStore* CLAPILandmarkStore::NewLC(const TCtorParams& aParams) +{ + JELOG2(EJavaLocation); + CLAPILandmarkStore* self = new(ELeave) CLAPILandmarkStore(aParams); + CleanupStack::PushL(self); + self->ConstructL(); + return self; +} + +// --------------------------------------------------------------------------- +// CLAPILandmarkStore::ReadFullLandmarkL +// --------------------------------------------------------------------------- +// +void CLAPILandmarkStore::ReadFullLandmarkL(CLAPILandmark& aLandmark) +{ + JELOG2(EJavaLocation); + // Check if the database has been closed + __ASSERT_ALWAYS(iLandmarkDatabase, User::Leave(KErrSessionClosed)); + + TLAPIItemId id = aLandmark.Id(); + // Check that the landmark id is valid + __ASSERT_DEBUG(id != KLAPINullItemId, LAPIError::Panic( + ELAPIPanicInvalidLandmarkId)); + + // Read the full landmark from the database and add it to the item + // Note that this overwrites the native entry in the item. The function + // leaves with KErrNotFound if there is no such item in the database + CPosLandmark* fullLandmark = iLandmarkDatabase->ReadLandmarkLC(id); + aLandmark.SetPosLandmark(fullLandmark); + // The ownership of fullLandmark is transferred to landmark object + CleanupStack::Pop(fullLandmark); +} + +// --------------------------------------------------------------------------- +// CLAPILandmarkStore::ReadLandmarkAttributesL +// --------------------------------------------------------------------------- +// +void CLAPILandmarkStore::ReadLandmarkAttributesL(CLAPILandmark& aLandmark, + const TUint aAttributes, const RArray* aAddressInfos) +{ + JELOG2(EJavaLocation); + // Check if the database has been closed + __ASSERT_ALWAYS(iLandmarkDatabase, User::Leave(KErrSessionClosed)); + + // Create new set of partial read parameters. The old parameters in the + // store will not be used since those can have additional fields which + // are not needed when reading the requested landmark data + CPosLmPartialReadParameters* params = CPosLmPartialReadParameters::NewLC(); + params->SetRequestedAttributes(aAttributes); + // Set requested address info fields if specified + if (aAddressInfos) + { + params->SetRequestedPositionFields(*aAddressInfos); + } + + TLAPIItemId id = aLandmark.Id(); + // Check that the landmark id is valid + __ASSERT_DEBUG(id != KLAPINullItemId, LAPIError::Panic( + ELAPIPanicInvalidLandmarkId)); + + // Read the landmark using the partial read parameters + iLandmarkDatabase->SetPartialReadParametersL(*params); + CleanupStack::PopAndDestroy(params); + // Read the partial landmark from the landmark database + CPosLandmark* newLm = iLandmarkDatabase->ReadPartialLandmarkLC(id); + // The ownership is transferred to landmark object + aLandmark.SetPosLandmark(newLm); + CleanupStack::Pop(newLm); +} + +// --------------------------------------------------------------------------- +// CLAPILandmarkStore::CategoryManager +// --------------------------------------------------------------------------- +// +MLAPICategoryManager* CLAPILandmarkStore::CategoryManagerL() const +{ + JELOG2(EJavaLocation); + // Check if the database has been closed + __ASSERT_ALWAYS(iLandmarkDatabase, User::Leave(KErrSessionClosed)); + return iCategoryManager; +} + +// --------------------------------------------------------------------------- +// CLAPILandmarkStore::LandmarkDisposed +// --------------------------------------------------------------------------- +// +void CLAPILandmarkStore::LandmarkDisposed(CLAPILandmark& aLandmark) +{ + JELOG2(EJavaLocation); + TInt landmarkIndex = iLandmarks.Find(&aLandmark); + // Remove the specified landmark if it was found from this store + if (landmarkIndex != KErrNotFound) + { + iLandmarks.Remove(landmarkIndex); + } +} + +// --------------------------------------------------------------------------- +// CLAPILandmarkStore::StoreUri +// --------------------------------------------------------------------------- +// +const TDesC& CLAPILandmarkStore::StoreUri() const +{ + JELOG2(EJavaLocation); + return *iStoreUri; +} + +// --------------------------------------------------------------------------- +// CLAPILandmarkStore::LandmarksL +// --------------------------------------------------------------------------- +// +CArrayPtr* CLAPILandmarkStore::LandmarksL( + const TUint aAttributes, const TLAPISearchCriteria* aSearchCriteria) +{ + JELOG2(EJavaLocation); + // Check if the database has been closed + __ASSERT_ALWAYS(iLandmarkDatabase, User::Leave(KErrSessionClosed)); + + CPosLmItemIterator* iter = iSearchFactory->CreateIteratorL(aSearchCriteria); + CleanupStack::PushL(iter); + // Do not initialize anything if there is nothing to initialize + TInt itemCount = iter->NumOfItemsL(); + // Ensure that the granularity is always more than zero. Flat array + // is used because the buffer will not be increased after it has + // been initialized + CArrayPtr* landmarks = new(ELeave) CArrayPtrFlat< + CLAPILandmark> (itemCount + 1); + CleanupStack::PushL(landmarks); + // Put the array to cleanup stack for reset and destroy since the + // array owns the objects and those must also be deleted + CleanupResetAndDestroyPushL(*landmarks); + + if (itemCount > 0) + { + // Get item identifiers only from the iterator + RArray ids; + CleanupClosePushL(ids); + iter->GetItemIdsL(ids, 0, iter->NumOfItemsL()); + + // Set partial read paramaters to the native database. + CPosLmPartialReadParameters* params = + CPosLmPartialReadParameters::NewLC(); + params->SetRequestedAttributes(aAttributes); + iLandmarkDatabase->SetPartialReadParametersL(*params); + CleanupStack::PopAndDestroy(params); + // Prepare partial landmarks. This reads the specified landmark id array + // from the native database and initializes the requested attributes to + // the previously read landmark objects. + CPosLmOperation* op = iLandmarkDatabase->PreparePartialLandmarksL(ids); + // ids are on top of the stack and are not needed anymore + CleanupStack::PopAndDestroy(&ids); + CleanupStack::PushL(op); + // Execute the operation. This needs to be done before the partial + // landmarks can be taken from the landmark database. The time of the + // operation depends on the partial read parameters set above + op->ExecuteL(); + + // The operation has been completed and prepared landmarks are available + CArrayPtr* preparedLandmarks = + iLandmarkDatabase->TakePreparedPartialLandmarksL(op); + CleanupStack::PopAndDestroy(op); + // Make this leave-safe since the prepared array cannot be put to + // cleanup stack safely because it needs two leaving operations + TRAPD(error, HandlePreparedLandmarksL(*preparedLandmarks, *landmarks)); + // Cleanup the prepared landmarks + preparedLandmarks->ResetAndDestroy(); + delete preparedLandmarks; + // Now it is safe to leave + User::LeaveIfError(error); + } + + CleanupStack::Pop(2, landmarks); // The object and ResetAndDestroy + CleanupStack::PopAndDestroy(iter); + return landmarks; +} + +// --------------------------------------------------------------------------- +// CLAPILandmarkStore::AddLandmarkL +// --------------------------------------------------------------------------- +// +void CLAPILandmarkStore::AddLandmarkL(CLAPILandmark& aLandmark) +{ + JELOG2(EJavaLocation); + // Check if the database has been closed + __ASSERT_ALWAYS(iLandmarkDatabase, User::Leave(KErrSessionClosed)); + TUint id = aLandmark.Id(); + LOG1(EJavaLocation, EInfo, "CLAPILandmarkStore::AddLandmarkL - id %d", id); + + CPosLandmark* landmark(NULL); + TRAPD(err, landmark = iLandmarkDatabase->ReadLandmarkLC(id); + CleanupStack::PopAndDestroy(landmark)); // We dont need the landmark + + // The landmark was not found from the database. Add a new landmark + if (err == KErrNotFound) + { + LOG(EJavaLocation, EInfo, + "CLAPILandmarkStore::AddLandmarkL - adding new landmark"); + // Prepare the landmark for saving. This will guarantee that partially + // read landmarks will be up to date when those are added to the native + // database. All data are not necessary available in the item if it has + // been partially loaded from the native database + aLandmark.PrepareForSaveL(); + + // Add new landmark to the database. Note that the added landmark + // should not initially belong to any categories + CPosLandmark& landmark = aLandmark.PosLandmark(); + landmark.RemoveLandmarkAttributes(CPosLandmark::ECategoryInfo); + iLandmarkDatabase->AddLandmarkL(landmark); + err = iLandmarks.Append(&aLandmark); + if (err != KErrNone) + { + // Remove the added landmark to keep the store in sync. Note + // that this call leaves only if the database hasn't been initialized + iLandmarkDatabase->RemoveLandmarkL(id); + User::Leave(err); + } + + // Mark that this landmark has been associated to a landmark store + aLandmark.AssociateToStore(this); + err = KErrNone; + // Compact the database if it is necessary + CompactIfNeededL(); + } + User::LeaveIfError(err); +} + +// --------------------------------------------------------------------------- +// CLAPILandmarkStore::UpdateLandmarkL +// --------------------------------------------------------------------------- +// +void CLAPILandmarkStore::UpdateLandmarkL(CLAPILandmark& aLandmark) +{ + JELOG2(EJavaLocation); + // Check if the database has been closed + __ASSERT_ALWAYS(iLandmarkDatabase, User::Leave(KErrSessionClosed)); + LOG1(EJavaLocation, EInfo, + "CLAPILandmarkStore::UpdateLandmarkL - id %d", + aLandmark.Id()); + // Refresh all landmarks before updating this landmark. This needs to be + // done because it is expected that all Java side landmark objects will + // not be updated if one specific landmark is updated + RefreshLandmarksL(aLandmark.Id()); + + // Prepare the landmark for saving. This will guarantee that partially + // read landmarks will be up to date when those are added to the native + // database. All data are not necessary available in the item if it has + // been partially loaded from the native database + aLandmark.PrepareForSaveL(); + // Update the existing landmark into the database. The existing data + // will be overwritten + iLandmarkDatabase->UpdateLandmarkL(aLandmark.PosLandmark()); + // Compact the database if it is necessary + CompactIfNeededL(); +} + +// --------------------------------------------------------------------------- +// CLAPILandmarkStore::DeleteLandmarkL +// --------------------------------------------------------------------------- +// +void CLAPILandmarkStore::RemoveLandmarkL(CLAPILandmark& aLandmark) +{ + JELOG2(EJavaLocation); + // Check if the database has been closed + __ASSERT_ALWAYS(iLandmarkDatabase, User::Leave(KErrSessionClosed)); + TUint32 id = aLandmark.Id(); + LOG1(EJavaLocation, EInfo, + "CLAPILandmarkStore::RemoveLandmarkL - id %d", id); + + // Refresh all related landmarks which match for the given landmark's id + TRAPD(err, RefreshLandmarksL(id, ETrue)); + // Do not leave if the landmark was already removed from the store + if (err == KErrNone) + { + LOG(EJavaLocation, EInfo, + "CLAPILandmarkStore::RemoveLandmarkL - removing from database"); + // Remove the landmark from the native database. + iLandmarkDatabase->RemoveLandmarkL(id); + // Compact the database if it is necessary + CompactIfNeededL(); + } + __ASSERT_ALWAYS(err == KErrNone || err == KErrNotFound, + User::Leave(err)); + // Not associated anymore. Remove from list + aLandmark.AssociateToStore(NULL); +} + +// --------------------------------------------------------------------------- +// CLAPILandmarkStore::CompactIfNeededL +// --------------------------------------------------------------------------- +// +void CLAPILandmarkStore::CompactIfNeededL() +{ + JELOG2(EJavaLocation); + // Check if the database has been closed + __ASSERT_ALWAYS(iLandmarkDatabase, User::Leave(KErrSessionClosed)); + + CPosLandmarkDatabase::TSize databaseSize = + iLandmarkDatabase->SizeL(); + // Execute synchronised compact operation if the the usage is below + // the minimum compact limit. This prevents that Landmarks Server will + // not do this operation and lock the database + if (databaseSize.iUsage < KLAPIMinCompactUsage) + { + ExecuteAndDeleteLD(iLandmarkDatabase->CompactL()); + } +} + +// --------------------------------------------------------------------------- +// CLAPILandmarkStore::Close +// --------------------------------------------------------------------------- +// +void CLAPILandmarkStore::Close() +{ + JELOG2(EJavaLocation); + TInt count = iLandmarks.Count(); + for (TInt i = 0; i < count; i++) + { + // The store has been closed. This indicates that there are no + // landmark objects in the java side and the landmark store has + // gone out of scope + iLandmarks[i]->StoreClosed(); + } + + // The landmark objects are not owned by the store + iLandmarks.Close(); + + delete iCategoryManager; + iCategoryManager = NULL; + delete iSearchFactory; + iSearchFactory = NULL; + delete iEventNotifier; + iEventNotifier = NULL; + delete iLandmarkDatabase; + iLandmarkDatabase = NULL; +} + +// --------------------------------------------------------------------------- +// CLAPILandmarkStore::HandlePreparedLandmarksL +// --------------------------------------------------------------------------- +// +void CLAPILandmarkStore::HandlePreparedLandmarksL(CArrayPtr< + CPosLandmark>& aSrcArray, CArrayPtr& aDestArray) +{ + JELOG2(EJavaLocation); + aDestArray.Reset(); + + // Create Location API landmark objects from each native landmark + TInt lmCount = aSrcArray.Count(); + while (lmCount-- > 0) + { + // Handle items in accending order from the start of the array + CPosLandmark* landmark = aSrcArray.At(0); + // The new landmark takes the ownership of the CPosLandmark object + // Associate the new landmark to this landmark store + CLAPILandmark::TCtorParams params; + params.iLandmark = landmark; + params.iLandmarkStore = this; + + CLAPILandmark* newLandmark = CLAPILandmark::NewLC(params); + // Remove the landmark from the prepared array since newLandmark + // takes the ownership of the returned value + aSrcArray.Delete(0); + aDestArray.AppendL(newLandmark); + CleanupStack::Pop(newLandmark); + iLandmarks.AppendL(newLandmark); + } +} + +// --------------------------------------------------------------------------- +// CLAPILandmarkStore::RefreshLandmarksL +// --------------------------------------------------------------------------- +// +void CLAPILandmarkStore::RefreshLandmarksL(TLAPIItemId aLandmarkId, + TBool aRemoveFromStore) +{ + JELOG2(EJavaLocation); + TInt landmarksCount = iLandmarks.Count(); + CPosLandmark* posLm = + iLandmarkDatabase->ReadLandmarkLC(aLandmarkId); + + // Refresh all landmarks which match for the given id. Iterate backwards + // if the landmarks are removed from the store + while (landmarksCount-- > 0) + { + CLAPILandmark* landmark = iLandmarks[landmarksCount]; + if (landmark->Id() == aLandmarkId) + { + CPosLandmark* copyLandmark = CPosLandmark::NewLC(*posLm); + landmark->SetPosLandmark(copyLandmark); + // The landmark takes the ownership of copyLandmark + CleanupStack::Pop(copyLandmark); + + // Remove the landmark from this store if requested. This is + // usually done because removed landmark must update all its + // duplicates since those landmarks must not be updated + if (aRemoveFromStore) + { + // The landmark disposes itself from this store + landmark->AssociateToStore(NULL); + } + } + } + + CleanupStack::PopAndDestroy(posLm); +} + +// --------------------------------------------------------------------------- +// CLAPILandmarkStore::CLAPILandmarkStore +// --------------------------------------------------------------------------- +// +CLAPILandmarkStore::CLAPILandmarkStore(const TCtorParams& aParams) : + iLandmarkDatabase(aParams.iLandmarkDatabase), iCategoryManager( + aParams.iCategoryManager), iEventNotifier( + aParams.iEventNotifier) +{ + JELOG2(EJavaLocation); +} + +// End of file