commsfwtools/preparedefaultcommsdatabase/src/MetaDatabaseVisitorRecordLink.cpp
changeset 0 dfb7c4ff071f
child 12 8b5d60ce1e94
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/commsfwtools/preparedefaultcommsdatabase/src/MetaDatabaseVisitorRecordLink.cpp	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,521 @@
+// File  MDBVisitorRecordLink.cpp
+//
+
+// 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:
+// Visitor that interacts with the central repository for CMDBRecordLink
+// A record link field in a record is treated as a field of type TMDBElementId
+// and is therefore handled by the standard visitor class
+// This class is for explicit MMetaDatabase calls on the CMDBRecordLink element itself
+// 
+//
+
+/**
+ @file
+ @internalComponent
+*/
+ 
+
+#include "CommsDatInternalDefs.h"
+#include <commsdattypesv1_1.h>
+#include <comms-infras/commsdatschema.h>
+
+
+using namespace CommsDat;
+using namespace CommsDatInternal;
+using namespace Meta;
+
+
+
+CommsDat::TMDBRecordLinkVisitor::TMDBRecordLinkVisitor(CMDBElement** aData)
+ /* note that data in base class will be set on SetOwner*/
+: CommsDat::TMDBVisitor<TInt>(NULL), iLinkedRecord(aData)
+/**
+ * Constructor
+ */
+    {
+    }
+
+
+CommsDat::TMDBRecordLinkVisitor* CommsDat::TMDBRecordLinkVisitor::NewL(const TAny* aMem, const TAny* aData)
+/**
+ * Instantiates a RecordSet Visitor of a particular type.
+ * Used for attribute registration (in the data v-table).
+ */
+    {
+    return static_cast<CommsDat::TMDBRecordLinkVisitor*>( ::new ((TUint8*)aMem) TMDBRecordLinkVisitor( (CMDBElement**)aData ) );
+    }
+
+
+TInt CommsDat::TMDBRecordLinkVisitor::Changed() const
+/*
+when this is not an int
+ composite class always returns changed so iterator will look for changed members.
+*/
+    {
+    if (iOwner && (iOwner->Type() != ELink ))
+        {
+        return TMDBVisitor<TInt>::Changed();
+        }
+
+    return 1;
+    }
+
+
+
+void CommsDat::TMDBRecordLinkVisitor::SetOwner(CMDBElement* aOwner)
+/*
+Set the owner of this element as is needed for callback.
+Also set a pointer to the value in the owner for convenience
+@internalComponent
+*/  
+	{ 
+    TMDBVisitorBase::SetOwner(aOwner);
+
+    // now set iTarget to have easy access to the link field value
+    if (iTarget == NULL)
+        {
+        iTarget = reinterpret_cast<SMDBMetaElement<TInt>*>(aOwner->Data());
+        }
+    }
+
+
+void CommsDat::TMDBRecordLinkVisitor::CheckLinkValueL(TMDBElementId aLinkedElementId)
+/*
+utility to check the value of this field specifies <Table><Record>.  
+Nothing less and nothing more.  
+Caller compliance and validation should already have got us to this point.
+
+@internalComponent
+*/     
+    {
+    if ( (aLinkedElementId & KCDMaskShowRecordType) == 0  ||
+         (aLinkedElementId & KCDMaskShowRecordId) == 0 ||
+         (aLinkedElementId & ~KCDMaskShowRecordTypeAndId) != 0 )
+        {
+        __FLOG_STATIC1(KLogComponent, KCDErrLog, 
+            _L("TMDBRecordLinkVisitor::CheckLinkedValueL() - link Value of <%08x> does not specify a table and record id and is not valid."), aLinkedElementId);
+        
+        User::Leave(KErrArgument);   
+        }        
+    }
+
+
+void CommsDat::TMDBRecordLinkVisitor::CheckLinkedRecordL(TMDBElementId aLinkedElementId)
+/*
+utility to check the linked record 
+
+@internalcomponent
+*/
+    {
+    if (iLinkedRecord != NULL  &&  *iLinkedRecord != NULL)
+        {
+        // just check the record is the right type
+        if ( (aLinkedElementId & KCDMaskShowRecordTypeAndId) != 
+             ((*iLinkedRecord)->ElementId() & KCDMaskShowRecordTypeAndId) )
+            {
+            __FLOG_STATIC2(KLogComponent, KCDErrLog, 
+                _L("TMDBRecordLinkVisitor::CheckLinkedRecordL() - TypeId given in field value <%08x> and type of linked record <%08x> do not match. Link not usable."), (aLinkedElementId & KCDMaskShowRecordType), (*iLinkedRecord)->TypeId() & KCDMaskShowRecordType);
+
+            User::Leave(KErrArgument);   
+            }
+        }
+    }
+
+void CommsDat::TMDBRecordLinkVisitor::MaintainBCForLegacyLinks()
+// yes this is a hack but need something to give clients the value 
+// they expect in order to maintain bc
+    {
+    if (iTarget->iValue > KCDMaxRecords)
+        {
+        if( ( (iTarget->iElementId & KCDMaskShowRecordType ) < KCDTIdAccessPointRecord    &&
+              (iTarget->iElementId & KCDMaskShowRecordType ) != KCDTIdWLANServiceExtRecord  ) )//||
+        //    (iTarget->iElementId & KCDMaskShowType ) == KCDTIdSelectionPolicy                 ||
+        //    (iTarget->iElementId & KCDMaskShowRecordType ) == KCDTIdApPrioritySelectionPolicyRecord  )
+            {
+            iTarget->iValue = ((iTarget->iValue & KCDMaskShowRecordId) >> 8);
+            }
+        }
+    }
+
+
+void CommsDat::TMDBRecordLinkVisitor::CreateLinkedRecordL(CMDBSession& aSession, TMDBElementId aLinkedElementId)
+/*
+utility to create the linked record 
+
+@internalcomponent
+*/
+    {
+    if (iLinkedRecord != NULL && *iLinkedRecord == NULL )
+        {
+
+        if ((aLinkedElementId & KCDMaskShowRecordType) == 0)
+            {
+            aLinkedElementId = CommsDatSchema::GetLinkIdL(aSession, iTarget->iElementId, iTarget->iValue, (*iLinkedRecord)? (*iLinkedRecord)->ElementId(): 0/*, iOwner*/);
+            }
+        // Create a new record of the appropriate type
+	    // trap is here to maintain behaviour compatibility
+	    TRAPD(err, *iLinkedRecord = CCDRecordBase::RecordFactoryL(aLinkedElementId & KCDMaskShowRecordType);)
+	    
+        if(err != KErrNone)
+	      	{
+			__FLOG_STATIC2(KLogComponent, KCDErrLog, _L("TMDBRecordLinkVisitor::MaybeCreateLinkedRecordL() Link Record creation for id <%08x> failed with err <%d>."), aLinkedElementId, err);
+           
+            User::Leave(err);    
+            }
+
+        (*iLinkedRecord)->SetElementId(aLinkedElementId | KCDMaskShowFieldType);
+        }
+    }
+
+TInt CommsDat::TMDBRecordLinkVisitor::GetL(CMDBSessionImpl* aSession) 
+/*
+Assumes fully resolved element Id but still needs mask for reserved bits
+
+@internalComponent
+*/
+    {
+    TInt err = TMDBVisitor<TInt>::GetL(aSession);
+   
+    if (err == KErrNone && iOwner->Type() != ELink)
+        {
+        MaintainBCForLegacyLinks();
+        }
+        
+	return err;
+    }
+
+TInt CommsDat::TMDBRecordLinkVisitor::LoadL(CMDBSessionImpl* aSession, TMDBElementId aRecordId, TMDBAttributeFlags aAttributeFlags) 
+/*
+Assumes type and record id set by caller
+
+@internalComponent
+*/
+    {
+    // First load the link id which is the value in this field 
+    TInt err = TMDBVisitor<TInt>::LoadL(aSession, (*iElementId & ~KCDMaskShowRecordId) | (aRecordId & KCDMaskShowRecordId), aAttributeFlags);
+    
+    if (iOwner->Type() == ELink &&
+        err == KErrNone )
+        {
+        if (iLinkedRecord != NULL && *iLinkedRecord != NULL)
+            {
+            CheckLinkedRecordL(iTarget->iValue);
+
+            (*iLinkedRecord)->SetRecordId(iTarget->iValue);
+
+            (*iLinkedRecord)->LoadL(aSession->iOwner);
+            }
+        else 
+            {
+            CreateLinkedRecordL(aSession->iOwner, iTarget->iValue);
+            if(*iLinkedRecord != NULL)
+            	{
+	            TRAPD(err, (*iLinkedRecord)->LoadL(aSession->iOwner));
+	            
+	            if (err != KErrNone)
+	                {
+	                delete *iLinkedRecord;
+	                *iLinkedRecord = NULL;
+	                }
+            	}
+            }
+        }
+
+    MaintainBCForLegacyLinks();
+    
+    return err;
+    }
+
+
+TInt CommsDat::TMDBRecordLinkVisitor::LoadL(CMDBSessionImpl* aSession, TMDBElementId aElementId, TMDBAttributeFlags aAttributeFlags, RArray<TUint32>& /*aIds*/)    
+/* 
+// KErrNoMatch
+// KErrNoAuthorisation
+
+@internalComponent
+*/
+    {      
+    return LoadL(aSession, aElementId, aAttributeFlags);
+    }   
+ 
+
+
+TInt CommsDat::TMDBRecordLinkVisitor::FindL(CMDBSessionImpl* aSession, RArray<TUint32>& aIds)
+/*
+Find fields checking whether the value matches the instantiated one if set.  The value must first be translated into
+the <table><record> format so that a match can be found.
+// KErrNoMatch
+// KErrNoAuthorisation
+ * 
+@internalComponent
+*/
+    {   
+    TInt err(KErrNone);
+
+    if ( iOwner->Type() == ELink &&
+         iLinkedRecord  != NULL  && 
+         *iLinkedRecord != NULL)
+        {
+        // Find the linked record
+
+        TBool found = (*iLinkedRecord)->FindL(aSession->iOwner);
+    
+        // set the value to match the record if it wasn't specifically changed
+        if ( found )
+            {
+            if (!TMDBVisitor<TInt>::Changed() )
+                {
+                iTarget->iValue = (*iLinkedRecord)->ElementId() & KCDMaskShowRecordTypeAndId;
+                Change();
+                }
+            else
+                {
+                CheckLinkedRecordL(iTarget->iValue);
+                }
+            }
+        else
+            {
+            err = KErrNotFound;
+            }
+        }
+      
+    // Then find the linking field
+    if ( err == KErrNone  &&  TMDBVisitor<TInt>::Changed() )
+        { 
+     
+        // first validate the linking field - have to trap in case is not valid
+        TInt temp(0);
+            
+ 
+            {
+            TRAPD(trapErr, temp = CommsDatSchema::GetLinkIdL(aSession->iOwner, iTarget->iElementId, 
+            								iTarget->iValue, (iLinkedRecord? (*iLinkedRecord)->ElementId(): 0), 
+            								iOwner ); );
+    
+            if (trapErr != KErrNone)
+                {
+                if (trapErr == KErrArgument)
+                    {
+                    return KErrNotFound;
+                    }
+                else
+                    {
+                    // some other error has occurred
+                    User::Leave(trapErr);
+                    }
+                }
+            }
+
+       // Now look for the field with the value of temp    
+
+        TInt mask = KCDMaskShowType;
+
+        // First look for the given value
+	    err = aSession->StorageL()->FindEqL(ElementId() & ~aSession->GetReadAttributeMask(), mask, temp, aIds);
+
+        if ( aIds.Count() <= 0 )
+            {
+            if (err == KErrNotFound)
+                {
+                // then try just looking for the value of the recordId on its own
+                err = aSession->StorageL()->FindEqL(ElementId() & ~aSession->GetReadAttributeMask(), mask, (temp & KCDMaskShowInstance), aIds);
+                }
+#ifdef __DEBUG // because only doing this for logging
+            if ( err != KErrNone  ||  aIds.Count() <= 0 )
+                {
+                if (err == KErrNone || err == KErrNotFound)
+                    {
+                    __FLOG_STATIC3(KLogComponent, KCDInfoLog, _L("TMDBRecordLinkVisitor::FindL() storage server FindEqL() did not find field <%08x>, value <%08x>"), ElementId(), iTarget->iValue, err);
+                    }
+                else
+                    {
+                    __FLOG_STATIC3(KLogComponent, KCDErrLog, _L("TMDBRecordLinkVisitor::FindL() storage server FindEqL() for field <%08x>, value <%08x>, returned unexpected err <%d>"), ElementId(), iTarget->iValue, err);
+                    }
+                }
+#endif             
+            }
+        }
+
+    return err;
+    }
+ 
+ 
+ 
+TInt CommsDat::TMDBRecordLinkVisitor::RefreshL(CMDBSessionImpl* aSession)
+/*
+Refresh existing data where it has not been changed
+// KErrNoMatch
+// KErrNoAuthorisation     
+
+@internalComponent
+*/
+    {         
+    if (! aSession || ! aSession->StorageL())
+        User::Leave(KErrNotReady);
+
+    TInt err(KErrGeneral); 
+    
+    //First refresh the field
+    if ( TMDBVisitor<TInt>::Changed() )
+        {
+        err = TMDBVisitor<TInt>::RefreshL(aSession);
+        }
+
+    if ( iOwner->Type() == ELink &&
+         err == KErrNone  &&
+         iLinkedRecord != NULL  && 
+         *iLinkedRecord != NULL )
+        {          
+        // Now refresh the linked record too
+
+        CheckLinkedRecordL(iTarget->iValue);
+
+        (*iLinkedRecord)->SetRecordId(iTarget->iValue);
+
+        (*iLinkedRecord)->RefreshL(aSession->iOwner);
+        }
+
+    if (! TMDBVisitor<TInt>::Changed())
+        {
+        MaintainBCForLegacyLinks();
+        }
+
+    return err;
+    }
+
+
+void CommsDat::TMDBRecordLinkVisitor::SetLinkValueL(CMDBSession& aSession)
+// always store the fully qualified link id (table and Record)
+    {
+ //   if ( (iTarget->iValue & KLinkableTag) != NULL)
+       // { // change the link value to table/record
+        iTarget->iValue = CommsDatSchema::GetLinkIdL(aSession, iTarget->iElementId, iTarget->iValue, 0/*, iOwner*/);
+   //     }
+   // else
+//        { // just validate the link
+    //    TInt temp = CommsDatSchema::GetLinkIdL(aSession, iTarget->iElementId, iTarget->iValue, NULL, iOwner);
+     //   }
+    }
+
+
+TInt CommsDat::TMDBRecordLinkVisitor::StoreL(CMDBSessionImpl* aSession, TMDBElementId aRecordId, TMDBAttributeFlags aAttributeFlags)
+/*
+Create a new linked field.
+If the linked record is also attached then create it as well if necessary.
+if the linked record is present it is assumed the client has changed it appropriately
+// KErrNoAuthorisation
+// KErrAlreadyExists
+@internalComponent
+*/
+    {         
+    if (! iTarget || ! iElementId || ! aSession->StorageL())
+        {
+        User::Leave(KErrNotReady);
+        }
+
+    if ( iTarget->iValue == 0)
+        {
+        return KErrNone; // pointless to store an empty link  
+        }
+
+    // First find the tableid of the linked field...
+
+    // Translate this link field into a storable element id <Table><Record> if enough information is present
+    SetLinkValueL(aSession->iOwner);
+
+ //   __FLOG_STATIC2(KLogComponent, KCDInfoLog, _L("TMDBRecordLinkVisitor StoreL() storing link value <%08x> in field <%08x>"), iTarget->iValue,  ElementId());
+  //  TUInt32 storeVal = iTarget->iValue > KCDMaxRecords ? (iTarget->iValue >> 8 ): iTarget->iValue)
+        
+    *iElementId = (*iElementId & ~KCDMaskShowRecordId) | (aRecordId & KCDMaskShowRecordId) | aAttributeFlags;            
+    TInt err = aSession->StorageL()->Create( ElementId() & KCDMaskHideRes, iTarget->iValue);
+   
+    if (err != KErrNone)
+        {
+        __FLOG_STATIC2(KLogComponent, KCDErrLog, _L("TMDBRecordLinkVisitor StoreL() storage server StoreL failed with err <%d> when storing field <%08x>"), err,  ElementId());
+        }
+    else if ( iOwner->Type() == ELink  &&
+              iLinkedRecord != NULL  &&  *iLinkedRecord != NULL )
+        {
+        // Now store the linked record too
+
+        // Check that the link value is consistent with the linked record
+        CheckLinkedRecordL(iTarget->iValue);
+        
+        (*iLinkedRecord)->SetRecordId(iTarget->iValue);
+
+        // ensure the record id is set and then call StoreL on the linked record
+        (*iLinkedRecord)->StoreL(aSession->iOwner); 
+        }
+
+    MaintainBCForLegacyLinks();
+    
+	return err;
+    }
+    
+ 
+TInt CommsDat::TMDBRecordLinkVisitor::ModifyL(CMDBSessionImpl* aSession, TMDBAttributeFlags aAttributeFlags)
+/*
+Modify field in the store
+Assumes that client has correctly changed the linkedRecord if changed the link value
+// KErrNoAuthorisation
+// KErrNoMatch
+@internalComponent
+*/
+    {         
+    if (! iElementId || ! aSession->StorageL())
+        {
+        User::Leave(KErrNotReady);
+        }
+    
+    TInt err = KErrNone;
+    
+    // First modify the link field which is the value in this field
+    if (0 == iTarget->iValue)
+    	{
+    	/* The value of a linked field is modified to 0. This means that instead of storing
+    	 * the 0 value the node (field) should be deleted from the DB.
+    	 */
+    	err = aSession->MaybeDeleteNodeL(NULL, iTarget->iElementId);
+    	return err;
+    	}
+    else
+    // Translate this link field into a storable element id <Table><Record> if enough information is present
+        {
+        SetLinkValueL(aSession->iOwner);
+        }
+        
+    err = TMDBVisitor<TInt>::ModifyL(aSession, aAttributeFlags);
+    
+    if (iOwner->Type() == ELink &&
+        err == KErrNone &&
+        iLinkedRecord != NULL  &&  *iLinkedRecord != NULL  )
+        {    
+        // Now modify the linked record too.
+
+        // it's the caller's responsibility to ensure the linkedRecord type matches the changed value
+        CheckLinkedRecordL(iTarget->iValue);
+        
+        (*iLinkedRecord)->SetRecordId(iTarget->iValue);
+
+        (*iLinkedRecord)->ModifyL(aSession->iOwner);
+        }
+        
+        MaintainBCForLegacyLinks();
+    
+    	return err;
+    }
+
+ 
+//EOF