authenticationservices/authenticationserver/source/server/evaluator.cpp
changeset 29 ece3df019add
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/authenticationservices/authenticationserver/source/server/evaluator.cpp	Tue Nov 24 09:06:03 2009 +0200
@@ -0,0 +1,410 @@
+/*
+* 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 the License "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: 
+*
+*/
+
+
+#include "authserver_impl.h"
+
+
+using namespace AuthServer;
+
+const CAuthExpressionImpl::TType CEvaluator::KAnd = CAuthExpressionImpl::EAnd;
+const CAuthExpressionImpl::TType CEvaluator::KOr = CAuthExpressionImpl::EOr;
+const TInt CEvaluator::KRPNGranularity = 4;
+
+// -------- (de)allocation --------
+
+
+CEvaluator* CEvaluator::NewL(MEvaluatorPluginInterface* aPluginInterface, MEvaluatorClientInterface* aClientInterface)
+/**
+	Factory function allocates and initializes new
+	instance of CEvaluator.
+	
+	@param	aPluginInterface	Used to invoke plugins.
+	@param	aClientInterface	Used to notify clients when
+								an evaluation has completed.
+ */
+	{
+	CEvaluator* ev = new(ELeave) CEvaluator(aPluginInterface, aClientInterface);
+	CleanupStack::PushL(ev);
+	ev->ConstructL();
+	CleanupStack::Pop(ev);
+	return ev;
+	}
+
+
+CEvaluator::CEvaluator(MEvaluatorPluginInterface* aPluginInterface, MEvaluatorClientInterface* aClientInterface)
+/**
+	Constructor records the supplied plugin and client interfaces.
+	
+	@param	aPluginInterface	Used to invoke plugins.
+	@param	aClientInterface	Used to notify clients when
+								an evaluation has completed.
+ */
+:	CActive(CActive::EPriorityStandard),
+	iPluginInterface(aPluginInterface),
+	iClientInterface(aClientInterface)
+//	,iRpnStack(0)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+
+void CEvaluator::ConstructL()
+/**
+	Allocate resources (i.e. RPN stack) used by
+	this object throughout its lifetime.
+ */
+	{
+	iRpnStack = new(ELeave) CArrayFixFlat<TIdentityId>(KRPNGranularity);
+	}
+
+
+CEvaluator::~CEvaluator()
+/**
+	Free any resources (i.e. RPN stack) successfully
+	allocated by this object.
+ */
+	{
+	Cancel();
+	delete iRpnStack;
+	}
+
+
+// -------- evaluation --------
+
+
+void CEvaluator::Evaluate(const CAuthExpressionImpl* aExpr)
+/**
+	Evaluate the current expression.  This finds
+	the leftmost leaf node from the supplied expression
+	and calls the appropriate plugin.
+ */
+	{
+	__ASSERT_DEBUG(!IsActive(),
+					Panic(EBusy));	
+	// iterate through left branches until find
+	// a leaf node
+	
+	while (aExpr->Type() == KAnd || aExpr->Type() == KOr)
+		{
+		aExpr = aExpr->Left();
+		}
+	
+	iCurrentNode = aExpr;
+	
+	if (aExpr->Type() == CAuthExpressionImpl::EPluginId)
+		iPluginInterface->Evaluate(aExpr->PluginId(), iIdentity, aExpr->Type(), iStatus);
+	else if (aExpr->Type() == CAuthExpressionImpl::ENull)
+		{
+		iPluginInterface->Evaluate(0, iIdentity, aExpr->Type(), iStatus);
+		}
+	else /* aExpr->Type() == CAuthExpression::EPluginType */
+		iPluginInterface->Evaluate(aExpr->PluginType(), iIdentity, aExpr->Type(), iStatus);
+	SetActive();
+	}
+
+
+void CEvaluator::RunL()
+/**
+	Implement CActive by recording the identity
+	returned by the plugin.  If the individual
+	plugin failed then fail the entire evaluation.
+ */
+	{
+	switch (iStatus.Int())
+	    {
+	    case KErrAuthServPluginNotActive:
+	        // don't break
+	    case KErrAuthServPluginCancelled:
+	        iIdentity = KUnknownIdentity;
+	        // don't break
+	    case KErrNone:
+	        EvaluatedNode(iIdentity);
+    		break;
+    	default: 
+    	    NotifyClientFailed(iStatus.Int());
+    	    break;
+	    }
+	}
+
+
+void CEvaluator::DoCancel()
+/**
+	Implement CActive.  This function does not
+	currently do anything.
+ */
+	{
+	iPluginInterface->CancelEvaluate();
+
+	NotifyClientFailed(KErrCancel);
+	}
+
+void CEvaluator::EvaluatedNode(TIdentityId aIdentity)
+/**
+	This function is called when the plugin has
+	returned an identity.
+	
+	If it is a root node then complete the client request.
+
+	If it is a left node, then push the identity on the
+	RPN stack and evaluate the right node.
+	
+	If it is a right node then combine it with the stacked
+	left result using the parent node's operator.
+ */
+	{
+	CAuthExpressionImpl* parent = iCurrentNode->Parent();
+	
+	// If parent node complete client request.
+	// This path is only used if the expression contains
+	// a single leaf node.  If the root node is complex
+	// then EvaluateCompound() calls HaveFinalResult().
+	if (parent == 0)
+		{
+		__ASSERT_DEBUG(RpnDepth() == 0, Panic(EENRpnStackNonZero));
+		NotifyClientSucceeded(aIdentity);
+		}
+	// if left node then push identity and evaluate sibling
+	else
+		{	
+		if (! PushIdentity(aIdentity))
+			NotifyClientFailed(KErrNoMemory);
+		else
+			{
+			const CAuthExpressionImpl* rhsExpr = parent->Right();
+			// if just evaluated RHS then compound result
+			if (rhsExpr == iCurrentNode)
+				{
+				EvaluateCompound(parent);
+				}
+			else if ( 	(aIdentity == KUnknownIdentity && parent->Type() == KAnd) || 
+						(aIdentity != KUnknownIdentity && parent->Type() == KOr)
+					)
+				{
+				if (! PushIdentity(aIdentity))
+					NotifyClientFailed(KErrNoMemory);
+				else
+					EvaluateCompound(parent);
+				}
+			// can't be short-circuited so evaluate RHS
+			else
+				{
+				Evaluate(rhsExpr);
+				}
+			}	// else (! PushIdentity(aIdentity))
+		}
+	}
+
+
+void CEvaluator::EvaluateCompound(const CAuthExpressionImpl* aParent)
+/**
+	This function is called by EvaluatedNode when
+	both the left and right identities are on the
+	RPN stack.
+	
+	Those two values are replaced with a single value
+	from the combining operator.
+ */
+	{
+	__ASSERT_DEBUG(RpnDepth() >= 2, Panic(EECRpnStackTooLow));
+	TIdentityId rhs = PopIdentity();
+	TIdentityId& lhs = LastIdentity();	// replace this with result
+	
+	switch (aParent->Type())
+		{
+	case KAnd:
+		// unknown if left and right don't match.
+		// These are both unknown for short-circuit.
+		if (lhs != rhs)
+			lhs = KUnknownIdentity;
+		break;
+	
+	case KOr:
+		// only take right value if left unknown.
+		// Both same non-unknown for short-circuit.
+		if (lhs == KUnknownIdentity)
+			lhs = rhs;
+		break;
+	
+	default:
+		__ASSERT_DEBUG(EFalse, Panic(EECBadParentType));
+		break;
+		}
+	
+	// combine the parent complex node with _its_ sibling
+	CAuthExpressionImpl* parent2 = aParent->Parent();
+
+	// if parent2 is the root node, then complete the client request
+	if (parent2 == 0)
+		{
+		__ASSERT_DEBUG(RpnDepth() == 1, Panic(EECRpnStackNotOneAtRoot));
+		// reset stack after notifying client because
+		// lhs is a reference to the top (only) item.
+		NotifyClientSucceeded(lhs);
+		}
+	
+	// if parent is parent2's left node then evaluate parent's right
+	// sibling.  At this point parent's result is on the stack.
+	else if (parent2->Left() == aParent)
+		{
+		// (lhs == unknown && type == AND) || (lhs != unknown && type == OR)
+		if ((lhs == KUnknownIdentity) == (parent2->Type() == KAnd))
+			{
+			if (! PushIdentity(lhs))
+				NotifyClientFailed(KErrNoMemory);
+			else
+				EvaluateCompound(parent2);
+			}
+		
+		else
+			Evaluate(parent2->Right());
+		}
+	
+	// parent must have been parent2's right child so combine
+	// its result with its left sibling.
+	else
+		{
+		__ASSERT_DEBUG(parent2->Right() == aParent, Panic(EECBadRightParent));
+		EvaluateCompound(parent2);
+		}
+	}
+
+
+// -------- client notification --------
+
+
+void CEvaluator::NotifyClientSucceeded(TIdentityId aIdentityId)
+/**
+	Notify the client that the evaluation has completed
+	successfully, and free the RPNStack.
+	
+	@param	aIdentityId		Identified user.  This can be KUnknownIdentity.
+ */
+	{
+	iClientInterface->EvaluationSucceeded(aIdentityId);
+	ResetRpnStack();
+	}
+
+
+void CEvaluator::NotifyClientFailed(TInt aReason)
+/**
+	Notify the client that the evaluation has failed
+	and free the RPN stack.
+	
+	@param	aReason			Symbian OS error code.
+ */
+	{
+	iClientInterface->EvaluationFailed(aReason);
+	ResetRpnStack();
+	}
+
+
+// -------- RPN stack --------
+
+
+TBool CEvaluator::PushIdentity(TIdentityId aIdentity)
+/**
+	Append the supplied entity to the RPN stack.
+	
+	@param	aIdentity		Function to append to the RPN stack.
+	@return					zero if could not append the item,
+							i.e. OOM, non-zero otherwise.
+ */
+	{
+	TRAPD(r, iRpnStack->AppendL(aIdentity));
+	return r == KErrNone;
+	}
+
+
+TIdentityId CEvaluator::PopIdentity()
+/**
+	Remove the last identity from the RPN stack
+	and return it.
+	
+	@return					The identity which was the last
+							item on the RPN stack when this
+							function was called.
+	@pre The RPN stack contains at least one identity.
+ */
+	{
+	TInt lastIndex = iRpnStack->Count() - 1;
+	TIdentityId id = iRpnStack->At(lastIndex);
+	
+	// This function will not leave because the array
+	// if not being grown.  It is only trapped to satisfy
+	// leavescan.
+	
+	TRAP_IGNORE(iRpnStack->ResizeL(lastIndex));
+	return id;
+	}
+
+
+TIdentityId& CEvaluator::LastIdentity()
+/**
+	Return a reference to the last item on the
+	RPN stack.  This function is defined so
+	ReplaceComplexIdentity() can efficiently
+	put a result on the RPN stack without reallocating.
+	
+	@return					Reference to last item on the RPN stack.
+	@pre The RPN stack contains at least one identity.
+ */
+	{
+	TInt lastIndex = iRpnStack->Count() - 1;
+	return iRpnStack->At(lastIndex);	
+	}
+
+
+void CEvaluator::ResetRpnStack()
+/**
+	Clear the RPN stack.
+ */
+	{
+	iRpnStack->Reset();
+	}
+
+
+#ifdef _DEBUG
+
+
+TInt CEvaluator::RpnDepth() const
+/**
+	Returns the depth of the RPN stack.  This is
+	defined for debug builds only to ensure the
+	stack depth is within an acceptable range.
+ */
+	{
+	return iRpnStack->Count();
+	}
+
+
+void CEvaluator::Panic(CEvaluator::TPanic aPanic)
+/**
+	Halt the current thread with the category "AUTHEVAL"
+	and the supplied reason.
+	
+	@param	aPanic			Panic reason.
+ */
+	{
+	_LIT(KPanicCat, "AUTHEVAL");
+	User::Panic(KPanicCat, aPanic);
+	}
+
+
+#endif	// #ifdef _DEBUG
+
+