appfw/apparchitecture/apserv/APSRECCACHE.cpp
changeset 0 2e3d3ce01487
child 72 56a7be608841
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "APSRECCACHE.h"
       
    17 #include "APSSES.H"
       
    18 
       
    19 //
       
    20 // Constants
       
    21 
       
    22 const TUint KMaxNumberOfEntries = 200;
       
    23 //
       
    24 
       
    25 CRecognitionResultHashMapEntry* CRecognitionResultHashMapEntry::NewL(const TDesC& aFileName, TTime aLastModified, const TDataRecognitionResult& aResult, CRecognitionResultHashMapEntry* aNext)
       
    26 	{
       
    27 	CRecognitionResult* result = CRecognitionResult::NewL(aFileName, aResult);
       
    28 	CleanupClosePushL(*result);
       
    29 	CRecognitionResultHashMapEntry* self = new(ELeave) CRecognitionResultHashMapEntry(aLastModified, result, aNext);
       
    30 	CleanupStack::Pop(result);	
       
    31 	return self;
       
    32 	}
       
    33 
       
    34 CRecognitionResultHashMapEntry::CRecognitionResultHashMapEntry(TTime aLastModified, CRecognitionResult* aResult, CRecognitionResultHashMapEntry* aNext)
       
    35 	: iLastModified(aLastModified), iResult(aResult), iNext(aNext)
       
    36 	{
       
    37 	}
       
    38 
       
    39 CRecognitionResultHashMapEntry::~CRecognitionResultHashMapEntry()
       
    40 	{
       
    41 	iResult->Close();
       
    42 	iResult = NULL;
       
    43 	delete iNext;
       
    44 	}
       
    45 
       
    46 void CRecognitionResultHashMapEntry::UpdateL(TTime aLastModified, const TDataRecognitionResult& aResult)
       
    47 	{
       
    48 	// since other objects  might have a pointer to the CRecognitionResult object
       
    49 	// and rely on the value not changing we need to create a new object to take 
       
    50 	// its place.
       
    51 	
       
    52 	CRecognitionResult* result = CRecognitionResult::NewL(FileName(), aResult);
       
    53 	iResult->Close();
       
    54 	iResult = result;
       
    55 	
       
    56 	iLastModified = aLastModified;
       
    57 	}
       
    58 
       
    59 //
       
    60 // CRecognitionResultHashMap
       
    61 //
       
    62 
       
    63 CRecognitionResultHashMap::CRecognitionResultHashMap()
       
    64 	{
       
    65 	}
       
    66 
       
    67 CRecognitionResultHashMap::~CRecognitionResultHashMap()
       
    68 	{
       
    69 	for(TUint i = 0; i < KFileHashMapEntries; i++)
       
    70 		{
       
    71 		delete Entry(i);
       
    72 		}
       
    73 	}
       
    74 
       
    75 CRecognitionResult* CRecognitionResultHashMap::Get(const TDesC& aKey, TTime& aLastModified) const
       
    76 	{
       
    77 	const TUint index = GetIndex(aKey);
       
    78 
       
    79 	for(const CRecognitionResultHashMapEntry* entry = Entry(index); entry; entry = entry->Next())
       
    80 		{
       
    81 		if(entry->FileName().Compare(aKey) == 0)
       
    82 			{
       
    83 			aLastModified = entry->LastModified();
       
    84 			return entry->Result();
       
    85 			}
       
    86 		}
       
    87 	return NULL;
       
    88 	}
       
    89 
       
    90 /**
       
    91 Adds a recognition result to the hash map of the particular directory.
       
    92 This is only done if it isn't already existing.
       
    93 The return value specifies if the number of entries was increased by one (ETrue) or not.
       
    94 @internalComponent
       
    95 */
       
    96 TBool CRecognitionResultHashMap::AddL(const TDesC& aKey, TTime aLastModified, const TDataRecognitionResult& aResult)
       
    97 	{
       
    98 	const TUint index = GetIndex(aKey);
       
    99 
       
   100 	//check if there already is an entry for the file
       
   101 	for(CRecognitionResultHashMapEntry* entry = Entry(index); entry; entry = entry->Next())
       
   102 		{
       
   103 		if(entry->FileName().Compare(aKey) == 0)
       
   104 			{
       
   105 			// already there -> check modification date
       
   106 			if( entry->LastModified() != aLastModified )
       
   107 				{
       
   108 				entry->UpdateL(aLastModified, aResult);
       
   109 				}
       
   110 
       
   111 			return EFalse;
       
   112 			}
       
   113 		}
       
   114 
       
   115 	//create new entry
       
   116 	SetEntry(index, CRecognitionResultHashMapEntry::NewL(aKey, aLastModified, aResult, Entry(index)));
       
   117 	iNumberOfEntries++;
       
   118 	return ETrue;
       
   119 	}
       
   120 	
       
   121 TUint CRecognitionResultHashMap::GetIndex(const TDesC& aKey) const
       
   122 	{
       
   123 	// That's the hash algorithm
       
   124 	TUint hash = aKey.Length();
       
   125 	for(TUint i=0;i< aKey.Length();i++)
       
   126 		{
       
   127 		hash += aKey[i];
       
   128 		}
       
   129 	return hash % KFileHashMapEntries;
       
   130 	}
       
   131 	
       
   132 
       
   133 //
       
   134 // CCacheDirectoryEntry
       
   135 //
       
   136 
       
   137 CCacheDirectoryEntry* CCacheDirectoryEntry::NewL(const TDesC& aDirectory)
       
   138 	{
       
   139 	CCacheDirectoryEntry* self = new(ELeave) CCacheDirectoryEntry;
       
   140 	CleanupStack::PushL(self);
       
   141 	self->iDirectory = aDirectory.AllocL();
       
   142 	CleanupStack::Pop(self);
       
   143 	return self;
       
   144 	}
       
   145 
       
   146 CCacheDirectoryEntry::CCacheDirectoryEntry()
       
   147 	{
       
   148 	}
       
   149 
       
   150 CCacheDirectoryEntry::~CCacheDirectoryEntry()
       
   151 	{
       
   152 	delete iDirectory;
       
   153 	}
       
   154 
       
   155 const TInt CCacheDirectoryEntry::iOffset = _FOFF(CCacheDirectoryEntry,iDlink);
       
   156 
       
   157 //
       
   158 // CApsRecognitionCache
       
   159 //
       
   160 
       
   161 CApsRecognitionCache::CApsRecognitionCache(RFs& aFs)
       
   162 	: iFs(aFs),
       
   163 	  iDirectoryHeader(CCacheDirectoryEntry::iOffset),
       
   164 	  iIter(iDirectoryHeader)
       
   165 	{
       
   166 	}
       
   167 
       
   168 CApsRecognitionCache::~CApsRecognitionCache()
       
   169 	{
       
   170     CCacheDirectoryEntry* anyitem;
       
   171     
       
   172     iIter.SetToFirst();
       
   173     while ((anyitem = iIter++) != NULL)
       
   174         {
       
   175         anyitem->iDlink.Deque();
       
   176         delete anyitem;
       
   177         };
       
   178 	}
       
   179 
       
   180 /**
       
   181 Adds a recognition result to the cache. An object is not added, when an up-to-date
       
   182 version is already in the cache or if it's not possible to check the file's LastModified().
       
   183 @internalComponent
       
   184 */
       
   185 void CApsRecognitionCache::AddL(const TDesC& aDirectory, const TDesC& aFileName, const TDataRecognitionResult& aRecognitionResult)
       
   186 	{
       
   187 	TTime lastModified;
       
   188 	TFileName fullFileName(aDirectory);
       
   189 	fullFileName.Append(aFileName);
       
   190 	if(iFs.Modified(fullFileName, lastModified) != KErrNone)
       
   191 		{
       
   192 	#if defined(_DEBUG)
       
   193 		RDebug::Print(_L("CApsRecognitionCache::AddL(): File '%S' was not added to the cache, cannot get the modified attribute (full filename is required for the cache to work)."), &fullFileName);
       
   194 	#endif
       
   195 		return;
       
   196 		}
       
   197 	DoAddL(aDirectory, aFileName, lastModified, aRecognitionResult);
       
   198 	}
       
   199  
       
   200 /**
       
   201 Adds a recognition result to the cache. An object is not added, when an up-to-date
       
   202 version is already in the cache or if it's not possible to check the file's LastModified().
       
   203 @internalComponent
       
   204 */
       
   205 void CApsRecognitionCache::AddL(const RFile& aFile, const TDesC& aDirectory, const TDesC& aFileName, const TDataRecognitionResult& aRecognitionResult)
       
   206 	{
       
   207 	TTime lastModified;
       
   208 	if(aFile.Modified(lastModified) != KErrNone)
       
   209 		{
       
   210 	#if defined(_DEBUG)
       
   211 		TFileName fullFileName(aDirectory);
       
   212 		fullFileName.Append(aFileName);
       
   213 		RDebug::Print(_L("CApsRecognitionCache::AddL(): File '%S' was not added to the cache, cannot get the modified attribute."), &fullFileName);
       
   214 	#endif
       
   215 		return;
       
   216 		}
       
   217 	DoAddL(aDirectory, aFileName, lastModified, aRecognitionResult);
       
   218 	}
       
   219 
       
   220 /**
       
   221 Adds a recognition result to the cache. An object is not added, when an up-to-date
       
   222 version is already in the cache or if it's not possible to check the file's LastModified().
       
   223 @internalComponent
       
   224 */
       
   225 void CApsRecognitionCache::DoAddL(const TDesC& aDirectory, const TDesC& aFileName, const TTime& aLastModified, const TDataRecognitionResult& aRecognitionResult)
       
   226 	{
       
   227 	if(iNumberOfEntries > KMaxNumberOfEntries)
       
   228 		{
       
   229 		Cleanup();
       
   230 		}
       
   231 		
       
   232 	CCacheDirectoryEntry* entry = NULL;
       
   233     iIter.SetToFirst();
       
   234     while ((entry = iIter++) != NULL)
       
   235     	{
       
   236 		if(CompareDirectories(entry->Directory(),aDirectory))
       
   237 			{
       
   238 			// move directory to top (it is likely to be used again soon)
       
   239 			entry->iDlink.Deque();
       
   240 			iDirectoryHeader.AddFirst(*entry);
       
   241 			break;
       
   242 			}
       
   243     	}
       
   244 
       
   245 	if(!entry)
       
   246 		{
       
   247 		// create directory and append it
       
   248 		entry = CCacheDirectoryEntry::NewL(aDirectory);
       
   249 		iDirectoryHeader.AddFirst(*entry);
       
   250 		}
       
   251 
       
   252 	// insert to correct directory
       
   253 	if(entry->Files().AddL(aFileName, aLastModified, aRecognitionResult))
       
   254 		{
       
   255 		iNumberOfEntries++;
       
   256 		}
       
   257 	}
       
   258 
       
   259 /**
       
   260 Searches the cache for the particular recognition result. If the file was not modified since the
       
   261 file was recognized, the stored recognition result is returned.
       
   262 @internalComponent
       
   263 */
       
   264 TBool CApsRecognitionCache::Get(const TDesC& aDirectory, const TDesC& aFileName, TDataRecognitionResult& aRecognitionResult)
       
   265 	{
       
   266 	TTime lastModified;
       
   267 	TFileName fileName(aDirectory);
       
   268 	fileName.Append(aFileName);
       
   269 	const TInt error = iFs.Modified(fileName, lastModified);
       
   270 	if(error != KErrNone) 
       
   271 		{
       
   272 		return EFalse;
       
   273 		}
       
   274 
       
   275 	CRecognitionResult* result = DoGet(aDirectory, aFileName, lastModified);
       
   276 	if(result)
       
   277 		{
       
   278 		result->Get(aRecognitionResult);
       
   279 		result->Close(); // decrease reference count since we're not exposing the object
       
   280 		return ETrue;
       
   281 		}
       
   282 	return EFalse;
       
   283 	}
       
   284 
       
   285 /**
       
   286 Searches the cache for the particular recognition result. If the file was not modified since the
       
   287 file was recognized, the stored recognition result is returned.
       
   288 
       
   289 N.B. The returned value is reference counted!
       
   290 @internalComponent
       
   291 */
       
   292 CRecognitionResult* CApsRecognitionCache::Get(const RFile& aFile, const TDesC& aDirectory, const TDesC& aFileName)
       
   293 	{	
       
   294 	TTime lastModified;
       
   295 	const TInt error = aFile.Modified(lastModified);
       
   296 	if(error != KErrNone)
       
   297 		{
       
   298 		return NULL;
       
   299 		}
       
   300 
       
   301 	return DoGet(aDirectory, aFileName, lastModified);
       
   302 	}
       
   303 
       
   304 /**
       
   305 Searches the cache for the particular recognition result. If the file was not modified since the
       
   306 file was recognized, the stored recognition result is returned.
       
   307 
       
   308 N.B. The returned value is reference counted!
       
   309 @internalComponent
       
   310 */
       
   311 CRecognitionResult* CApsRecognitionCache::DoGet(const TDesC& aDirectory, const TDesC& aFileName, const TTime& aLastModified)
       
   312 	{	
       
   313 	CRecognitionResult* result = NULL;
       
   314 	CCacheDirectoryEntry* entry;
       
   315 
       
   316     iIter.SetToFirst();
       
   317     while ((entry = iIter++) != NULL)
       
   318     	{
       
   319     	if(CompareDirectories(entry->Directory(),aDirectory))
       
   320     		{
       
   321     		TTime cachedLastModified;
       
   322 			result = entry->Files().Get(aFileName, cachedLastModified);
       
   323 			if(result)
       
   324 				{
       
   325 				if(cachedLastModified != aLastModified)
       
   326 					{
       
   327 					result->Close();
       
   328 					result = NULL;
       
   329 					}
       
   330 				}
       
   331 
       
   332 			// move directory to top (it is likely to be used again soon)
       
   333 			entry->iDlink.Deque();
       
   334 			iDirectoryHeader.AddFirst(*entry);
       
   335 			break;
       
   336     		}
       
   337     	}
       
   338 	return result;
       
   339 	}
       
   340 
       
   341 /**
       
   342 A fast comparison of two directory names.
       
   343 Should be faster than the "normal" TDesC16::Compare function, because
       
   344 there is no need to check which string is "greater".
       
   345 @internalComponent
       
   346 */
       
   347 TBool CApsRecognitionCache::CompareDirectories(const TDesC& aDir1, const TDesC& aDir2) const
       
   348 	{
       
   349 	TBool equal = ETrue;
       
   350 	if(aDir1.Length() == aDir2.Length())
       
   351 		{
       
   352 		// start with the last character, as directories tend to be the same at the beginning
       
   353 		for(TInt i=aDir1.Length()-1; i>=0; i--)
       
   354 			{
       
   355 			if(aDir1[i] != aDir2[i])
       
   356 				{
       
   357 				// return as soon one character is "wrong"
       
   358 				equal = EFalse;
       
   359 				break;
       
   360 				}
       
   361 			}
       
   362 		}
       
   363 	else
       
   364 		{
       
   365 		equal = EFalse;
       
   366 		}
       
   367 	return equal;
       
   368 	}
       
   369 /**
       
   370 Removes the least-often used directory in the cache.
       
   371 @internalComponent
       
   372 */
       
   373 void CApsRecognitionCache::Cleanup()
       
   374 	{
       
   375     CCacheDirectoryEntry* item = iDirectoryHeader.Last();
       
   376     iNumberOfEntries -= item->NumberOfEntries();
       
   377     item->iDlink.Deque();
       
   378     delete item;
       
   379 	}
       
   380 
       
   381 /**
       
   382 Empties the cache. Useful mainly for testing.
       
   383 @internalComponent
       
   384 */
       
   385 void CApsRecognitionCache::Flush()
       
   386 	{
       
   387 	while(!iDirectoryHeader.IsEmpty())
       
   388 		{
       
   389 		Cleanup();
       
   390 		}
       
   391 	}