webservices/wsibasicplugin/src/senbasicwebservicesession.cpp
changeset 0 62f9d29f7211
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webservices/wsibasicplugin/src/senbasicwebservicesession.cpp	Thu Jan 07 16:19:19 2010 +0200
@@ -0,0 +1,529 @@
+/*
+* Copyright (c) 2002-2005 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:           
+*
+*/
+
+
+
+
+
+
+
+
+
+
+
+// INCLUDE FILES
+#include "senbasicwebservicesession.h"
+#include "SenHttpTransportProperties.h" // could be system included (ADO task)
+#include "senservicesession.h"
+#include "SenSoapMessage.h"
+#include "SenSoapConstants.h"           // KSenSoapActionHeaderName
+#include "senwsdescription.h"
+#include "msencoreservicemanager.h"
+#include "msenremoteserviceconsumer.h"
+#include "SenXmlUtils.h"
+#include "SenDateUtils.h"
+#include "msentransport.h"
+#include "SenServiceConnection.h"
+#include "sendebug.h"
+#include "senlogger.h"
+#include <SenSoapFault.h>
+
+
+CSenBasicWebServiceSession* CSenBasicWebServiceSession::NewL(MSIF& aFramework)
+    {
+    CSenBasicWebServiceSession* pNew =
+        CSenBasicWebServiceSession::NewLC(aFramework);
+    CleanupStack::Pop();
+    return pNew;
+    }
+
+CSenBasicWebServiceSession* CSenBasicWebServiceSession::NewLC(MSIF& aFramework)
+    {
+    CSenBasicWebServiceSession* pNew =
+        new (ELeave) CSenBasicWebServiceSession(EBasicWebServiceSession,
+                                                aFramework);
+    CleanupStack::PushL(pNew);
+    // bugfix 2004-09-08,
+    // removed faulty call to CSenServiceSession::BaseConstructL
+    pNew->ConstructL();
+    return pNew;
+    }
+
+CSenBasicWebServiceSession::CSenBasicWebServiceSession(
+                                        TDescriptionClassType aType,
+                                        MSIF& aFramework)
+:
+CSenWebServiceSession(aType, aFramework)
+    {
+    }
+
+void CSenBasicWebServiceSession::ConstructL()
+    {
+    // Sets the local name to "ServiceDescription" and initiates the inner ipElement
+    CSenWebServiceSession::ConstructL();
+    }
+
+CSenBasicWebServiceSession::~CSenBasicWebServiceSession()
+    {
+    }
+
+// Override compute status to make BWS sessions to be ALWAYS valid (ready)
+TInt CSenBasicWebServiceSession::ComputeStatusL()
+    {
+    // session is ready, if an endpoint is defined
+    return CSenServiceSession::ComputeStatusL();
+    }
+    
+TInt CSenBasicWebServiceSession::InitializeFromL(MSenServiceDescription& aServiceDescription)
+    {
+    TLSLOG(KSenCoreServiceManagerLogChannelBase  , KMinLogLevel,(_L("CSenWebServiceSession::InitializeFromL")));
+    
+    // Call superclass method to initialize facets, transport (endpoint) cue, etc..
+	TInt retVal = CSenWebServiceSession::InitializeFromL(aServiceDescription);
+    CSenWSDescription& xmlSD = (CSenWSDescription&)aServiceDescription;
+    TPtrC8 transportCue = xmlSD.TransportCue();
+    if( transportCue.Length() > 0 )
+        {
+        SetTransportCueL( transportCue );
+        }
+	return retVal;
+    }
+    
+
+TInt CSenBasicWebServiceSession::SubmitSoapL( const TDesC8& aSoapMessage, 
+                                              const TDesC8& aTransportProperties,
+                                              MSenRemoteServiceConsumer& aConsumer,
+                                              HBufC8*& aResponse )
+    {
+    CSLOG_L(aConsumer.ConnectionId()  , KMinLogLevel,"CSenWsiPlugin::RegisterServiceDescriptionL");
+    CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"CSenBasicWebServiceSession::SubmitSoapL(TDesC8&)");
+	TPtrC8 endpoint = Endpoint();
+#ifdef _SENDEBUG
+    CSLOG_L(aConsumer.ConnectionId() , KMaxLogLevel,"///////////////////////////////////////////////////////");
+    CSLOG_FORMAT((aConsumer.ConnectionId()  , KMinLogLevel, _L8("- Endpoint: %S"), &endpoint));
+	CSLOG_FORMAT((aConsumer.ConnectionId()  , KMaxLogLevel, _L8("- Message (%d bytes):"), aSoapMessage.Length()));
+    CSLOG_ALL(aConsumer.ConnectionId() , KMaxLogLevel,( aSoapMessage ));
+    CSLOG_L(aConsumer.ConnectionId() , KMaxLogLevel,"///////////////////////////////////////////////////////");
+#endif
+
+    MSenTransport& transport = aConsumer.TransportL();
+    SetFrameworkPropertiesL( transport );
+    TInt retVal = transport.SubmitL( endpoint, aSoapMessage, aTransportProperties, aResponse, aConsumer);
+    
+    if(!aResponse)
+        {
+        // response was NULL: probably either out
+        // of heap or some transport malfunction.
+        return retVal;
+        }
+    else if(aResponse->Length() < KSenSoapEnvelopeName().Length()*2)
+        {
+        // no use parsing, Envelope -root element not there
+        // deliver non-soap body to consumer
+        return retVal;
+        }
+
+    CleanupStack::PushL(aResponse);
+
+    CSenSoapMessage* pResponseSoapMsg = NULL;
+    TInt leaveCode(KErrNone);
+
+    // attempt to parse the response
+    // here. SOAP faults are to be
+    // searched after,
+
+    TInt parseRetCode(KErrNone);
+    TRAP( leaveCode, (parseRetCode =
+        ParseResponseL(*aResponse, pResponseSoapMsg)) );
+
+    if(leaveCode!=KErrNone)
+        {
+        // THE RESPONSE could not be parsed
+        delete pResponseSoapMsg;
+
+        // THE RESPONSE IS NOT SOAP
+        if(retVal==KErrNone)
+            {
+            // indicate with return value, that response is
+            // invalid - even though submit was ok, the
+            // response could NOT be parsed!
+            retVal = leaveCode;
+            }
+        CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"(NOK) Response is not a SOAP message");
+        }
+    else
+        {
+
+        if (parseRetCode != KErrNone)
+            {
+            CSLOG_FORMAT((aConsumer.ConnectionId()  , KMinLogLevel, _L8("(NOK) Parsing SOAP msg failed (%d)"),
+                    parseRetCode));
+
+            if(retVal==KErrNone) // submit was ok
+                {
+                // indicate with return value, that response is
+                // invalid - even though submit was ok, the
+                // response could NOT be parsed!
+                retVal = parseRetCode;
+                }
+
+            // THE RESPONSE could not be parsed
+            delete pResponseSoapMsg;
+            }
+        else
+            {
+            CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"WS-I: (OK) Response is a SOAP message");
+            CleanupStack::PushL(pResponseSoapMsg);
+
+            TBool completeServerMessages(ETrue);
+            HasFacetL(KCompleteMessagesFacet, completeServerMessages);
+
+            // response is OK and in SOAP form.
+			if(pResponseSoapMsg)
+				{
+				if (pResponseSoapMsg->IsFault())
+					{
+					// response is SOAP fault
+					CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"WS-I: Response is a SOAP fault.");
+					retVal = KErrSenSoapFault;
+
+                if (!completeServerMessages)
+                    {
+                    CleanupStack::Pop(pResponseSoapMsg);
+                    // try to detach the SOAP fault
+                    HBufC8* pDetached = NULL;
+                    retVal = HandleSoapFaultL(pResponseSoapMsg, pDetached);
+                    if(retVal == KErrSenSoapFault || retVal == KErrNone)
+                        {
+                        // KErrNone means that original fault was handled
+                        // properly and we now have the wanted result 
+                        // and consumer may receive it (message body)
+
+                        // Note: currently we don't handle any SOAP faults
+                        // in WebServiceSession class, so KErrNone should
+                        // not be returned. The OR clause (||) here is 
+                        // only for future extensions.
+                        delete aResponse;
+                        aResponse = NULL;
+                        aResponse = pDetached;
+                        pDetached = NULL;
+                        }
+                    else if(retVal == KErrNotFound)
+                        {
+
+                        // SOAP fault element  could not be found
+                        CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"WS-I: Major; SOAP fault element not found \
+                                    even though assumed SOAP fault.");
+                        retVal = KErrSenInternal;
+                        }
+
+						}
+					else
+						{
+						CleanupStack::PopAndDestroy(pResponseSoapMsg);
+						}
+					}
+				else
+					{
+					// Check complete server messages on/off
+					if (!completeServerMessages)
+						{
+						HBufC8* pBody = pResponseSoapMsg->BodyAsStringL();
+						if(pBody)
+							{
+							delete aResponse;
+							aResponse = NULL;
+							aResponse = pBody;
+							pBody = NULL;
+							CSLOG_L(aConsumer.ConnectionId() , KNormalLogLevel,"- Detached SOAP message body.");
+							}
+						}
+					CleanupStack::PopAndDestroy(pResponseSoapMsg);
+					}
+				}
+			}
+		}
+#ifdef _SENDEBUG
+    if(aResponse)
+        {
+        CleanupStack::PushL(aResponse);
+        CSLOG_L(aConsumer.ConnectionId() , KNormalLogLevel,"- Detached SOAP message body.");
+        CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"CSenBasicWebServiceSession::SubmitSoapL:");
+        CSLOG_FORMAT((aConsumer.ConnectionId()  , KNormalLogLevel, _L8("- Response (%d bytes):"), 
+            aResponse->Length()));
+        CSLOG_ALL(aConsumer.ConnectionId() , KMaxLogLevel,(*aResponse));
+        CSLOG_L(aConsumer.ConnectionId() , KMaxLogLevel,"--------------------------------------------------");
+        CleanupStack::Pop(); // aResponse
+        }
+#endif
+    CleanupStack::Pop(); // aResponse
+    return retVal;
+    }
+
+TInt CSenBasicWebServiceSession::SendSoapL( const TDesC8& aSoapMessage, 
+                                            const TDesC8& aTransportProperties,
+                                            MSenRemoteServiceConsumer& aConsumer,
+                                            TInt& aTxnId,
+                                            HBufC8*& /*aRevalidationError*/ ) 
+    {
+	TPtrC8 endpoint = Endpoint();
+#ifdef _SENDEBUG
+    CSLOG_L(aConsumer.ConnectionId() , KMaxLogLevel,"///////////////////////////////////////////////////////");
+    CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"CSenBasicWebServiceSession::SendSoapL:");
+    CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"- Endpoint:");
+	TLSLOG(aConsumer.ConnectionId()  , KMinLogLevel,( endpoint ));
+	CSLOG_FORMAT((aConsumer.ConnectionId()  , KMaxLogLevel, _L8("- Message (%d bytes):"), aSoapMessage.Length()));
+    CSLOG_ALL(aConsumer.ConnectionId() , KMaxLogLevel,(aSoapMessage));
+    CSLOG_L(aConsumer.ConnectionId() , KMaxLogLevel,"///////////////////////////////////////////////////////");
+#endif
+    MSenTransport& transport = aConsumer.TransportL();
+    SetFrameworkPropertiesL( transport );
+    TInt retVal = transport.SendL( endpoint, 
+                                   aSoapMessage, 
+                                   aTransportProperties, 
+                                   *this, 
+                                   aConsumer, 
+                                   aTxnId );
+    CSLOG_FORMAT((aConsumer.ConnectionId()  , KNormalLogLevel, _L8("- Transaction id: %d"), aTxnId));
+    return retVal;
+    }
+    
+TInt CSenBasicWebServiceSession::HttpMethodFromPropertiesL( const TDesC8& aProperties,
+                                                            CSenHttpTransportProperties::TSenHttpMethod& aMethod )
+    {
+    TInt retVal(KErrNotFound);
+    if ( aProperties.Length() > 0 && aProperties.Find(KHttpMethodLocalName)!= KErrNotFound && 
+        (aProperties.Find(KHttpGet)!= KErrNotFound || aProperties.Find(KHttpDelete)!= KErrNotFound) ) 
+        {
+        // Properties strings are found, now use CSenHttpProperties instance to validate that HTTP
+        // method really is either HTTP GET or HTTP DELETE:
+        CSenHttpTransportProperties* pHttpProperties = CSenHttpTransportProperties::NewLC(); // push tp
+        
+        // Parse aProperties into HTTP transport properties object:
+        TInt leaveCode( KErrNone );
+        TRAP( leaveCode, pHttpProperties->ReadFromL( aProperties ); )
+        if ( leaveCode == KErrNone )
+            {
+            CSenHttpTransportProperties::TSenHttpMethod method;
+            retVal = pHttpProperties->HttpMethodL( method );
+            if ( retVal == KErrNone )
+                {
+                aMethod = method;
+                }
+#ifdef _SENDEBUG            
+            else 
+                {
+                // HttpMethodL failed:
+                TLSLOG_FORMAT((KSenCoreServiceManagerLogChannelBase  , KMinLogLevel, _L8("- HttpMethodL call failed. Error code: (%d)"), retVal));
+                }
+#endif // _SENDEBUG            
+            }
+#ifdef _SENDEBUG            
+        else 
+            {
+            // ReadFromL leaved:
+            TLSLOG_FORMAT((KSenCoreServiceManagerLogChannelBase  , KMinLogLevel, _L8("- Reading (parsing) of HTTP properties failed. Leave code: (%d)"), leaveCode));
+            
+            }
+#endif // _SENDEBUG            
+        CleanupStack::PopAndDestroy( pHttpProperties ); // de-alloc tp
+        }
+    return retVal;
+    }
+    
+    
+
+/*
+* @param aMessage contains request which is parsed into a SoapEnvelope object using
+*                 CSenWebServiceSession::MessageForSendingL and then SendSoapL is called  
+*/
+TInt CSenBasicWebServiceSession::SendL( const TDesC8& aMessage, 
+                                        const TDesC8& aTransportProperties,
+                                        MSenRemoteServiceConsumer& aConsumer,
+                                        TInt& aTxnId,
+                                        HBufC8*& aRevalidationError )
+    {
+    CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"CSenBasicWebServiceSession::SendL(TDesC8&, ...)");
+#ifdef _SENDEBUG
+    CSLOG_L(aConsumer.ConnectionId() , KMaxLogLevel,"///////////////////////////////////////////////////////");
+	TPtrC8 endpoint = Endpoint();
+	CSLOG_FORMAT((aConsumer.ConnectionId()  , KMinLogLevel, _L8("- Endpoint: %S"), &endpoint));
+	CSLOG_FORMAT((aConsumer.ConnectionId()  , KMaxLogLevel, _L8("- Message (%d bytes):"), aMessage.Length()));
+    CSLOG_ALL(aConsumer.ConnectionId() , KMaxLogLevel,( aMessage ));
+    CSLOG_L(aConsumer.ConnectionId() , KMaxLogLevel,"///////////////////////////////////////////////////////");
+#endif
+    TInt retVal(KErrNone);
+
+    // First check if HTTP GET or DELETE has been spesified via transport properties:
+    // -- in such case, the raw descriptor should be sent "as it is", without wrapping
+    // it inside SOAP Body. This way WS-I can support HTTP GET and DELETE and still
+    // validate that response(s) are SOAP (unlike REST, which does no response validation).
+
+    CSenHttpTransportProperties::TSenHttpMethod httpMethod;
+    TInt readHttpMethodRetVal = HttpMethodFromPropertiesL( aTransportProperties, httpMethod );
+
+    if ( readHttpMethodRetVal == KErrNone && 
+         httpMethod == CSenHttpTransportProperties::ESenHttpGet || 
+         httpMethod == CSenHttpTransportProperties::ESenHttpDelete )
+        {
+        // Perform direct call to service session (and not to web service session!)
+        retVal = CSenServiceSession::SendL( aMessage, aTransportProperties, aConsumer, aTxnId, aRevalidationError);
+        }
+    else
+        {
+        // The request data (UTF-8 descriptor) is expected to be serialized content
+        // for SOAP Body and HTTP GET/DELETE is not taking place. 
+        // Proceed in standard way and parse the request with SOAP-ENV:
+    	CSenSoapMessage* pMsg = NULL;
+        retVal = CSenWebServiceSession::MessageForSendingL( aMessage, aConsumer.Id(), pMsg );
+        CleanupStack::PushL( pMsg );
+        if ( retVal!=KErrNone )
+            {
+            CSLOG_FORMAT((aConsumer.ConnectionId()  , KMinLogLevel, _L8("- MessageForSendingL returned an error: %d"), retVal));
+            CleanupStack::PopAndDestroy( pMsg );
+            }
+        else // no error
+            {
+            HBufC8* pSoapMsg = pMsg->AsXmlL();
+            CleanupStack::PopAndDestroy( pMsg ); 
+            CleanupStack::PushL( pSoapMsg ); 
+            retVal = SendSoapL( *pSoapMsg, aTransportProperties, aConsumer, aTxnId, aRevalidationError);
+            CleanupStack::PopAndDestroy( pSoapMsg );
+            }
+        }
+    return retVal;
+    }
+
+/*
+* aMessage contains request which is parsed into a SoapEnvelope object using
+* CSenWebServiceSession::MessageForSendingL and then SubmitSoapL is called  
+*/
+TInt CSenBasicWebServiceSession::SubmitL( const TDesC8&  aMessage, 
+                                          const TDesC8&  aTransportProperties ,
+                                          MSenRemoteServiceConsumer&  aConsumer ,
+                                          HBufC8*& aResponse )
+    {
+    CSLOG_L(aConsumer.ConnectionId() , KMinLogLevel,"CSenBasicWebServiceSession::SubmitL(TDesC8&, ...)");
+#ifdef _SENDEBUG
+    CSLOG_L(aConsumer.ConnectionId() , KMaxLogLevel,"///////////////////////////////////////////////////////");
+	TPtrC8 endpoint = Endpoint();
+	CSLOG_FORMAT((aConsumer.ConnectionId()  , KMinLogLevel, _L8("- Endpoint: %S"), &endpoint));
+	CSLOG_FORMAT((aConsumer.ConnectionId()  , KMaxLogLevel, _L8("- Message (%d bytes) about to submit:"), aMessage.Length()));
+	CSLOG_ALL(aConsumer.ConnectionId() , KMaxLogLevel,( aMessage ));
+	CSLOG_L(aConsumer.ConnectionId() , KMaxLogLevel,"///////////////////////////////////////////////////////");
+#endif
+    TInt retVal(KErrNone);
+    CSenHttpTransportProperties::TSenHttpMethod httpMethod;
+    TInt readHttpMethodRetVal = HttpMethodFromPropertiesL( aTransportProperties, httpMethod );
+
+    if ( readHttpMethodRetVal == KErrNone && 
+         httpMethod == CSenHttpTransportProperties::ESenHttpGet || 
+         httpMethod == CSenHttpTransportProperties::ESenHttpDelete )
+        {
+        // Perform direct call to service session (and not to web service session!)
+        retVal = CSenServiceSession::SubmitL( aMessage, aTransportProperties, aConsumer, aResponse);
+        }
+    else
+        {
+        CSenSoapMessage* pMsg = NULL;
+        retVal = CSenWebServiceSession::MessageForSendingL( aMessage, aConsumer.Id(), pMsg );
+        CleanupStack::PushL(pMsg);
+        if ( retVal!=KErrNone )
+            {
+            CSLOG_FORMAT((aConsumer.ConnectionId()  , KMinLogLevel, _L8("- MessageForSendingL returned an error: %d"), retVal));
+            CleanupStack::PopAndDestroy( pMsg );
+            }
+        else // no error
+            {
+            HBufC8* pSoapMsg = pMsg->AsXmlL();
+            CleanupStack::PopAndDestroy( pMsg ); // de-alloc SOAP object after de-serialization
+            CleanupStack::PushL( pSoapMsg );
+            retVal = SubmitSoapL( *pSoapMsg, aTransportProperties, aConsumer, aResponse );
+            CleanupStack::PopAndDestroy( pSoapMsg );
+            }
+        }
+	return retVal; 
+   }
+
+
+TBool CSenBasicWebServiceSession::HasSuperClass( TDescriptionClassType aType )
+    {
+    if( aType == MSenServiceDescription::EWebServiceSession ) // direct superclass!
+        {
+        // If asked type is the know *direct* father/mother, return true:
+        return ETrue; 
+        } 
+    else
+        { 
+        // Otherwise, ask from direct superclass (may invoke chain of recursive calls)
+        return CSenWebServiceSession::HasSuperClass( aType ); 
+        }
+    }
+
+
+// TEMPORARY: remove when "message context"- and "transport factory taking 
+// properties from all layers"- tasks are ready
+TInt CSenBasicWebServiceSession::SetFrameworkPropertiesL(MSenTransport& aTransport)
+    {
+    return iFramework.SetTransportPropertiesL(aTransport);
+    }
+TInt CSenBasicWebServiceSession::HandleSoapFaultL(CSenSoapMessage* apSOAPMessage,
+                                            const TInt aErrorCode,
+                                            const TInt aTxnId,
+                                            MSenRemoteServiceConsumer& aConsumer,
+                                            MSenProperties* aResponseTransportProperties)
+	{
+    LOG_WRITE_L("CSenBasicWebServiceSession::HandleSoapFaultL ");
+
+    TInt retVal(KErrNone);
+    
+    if ( apSOAPMessage )
+        {
+        	CleanupStack::PushL( apSOAPMessage ); 
+	        CSenSoapFault* pDetached = apSOAPMessage->DetachFaultL();
+	        if(pDetached)
+	            {
+	            LOG_WRITE_L("Detached a SOAP fault");
+	            CleanupStack::PushL(pDetached);
+	            HBufC8* pAsXml = pDetached->AsXmlL();
+	            if(pAsXml)
+	                {
+	                aConsumer.HandleErrorL(pAsXml, KErrSenSoapFault, aTxnId, aResponseTransportProperties);
+	                }
+	            CleanupStack::PopAndDestroy();
+	            retVal = KErrNone; 
+	            }
+	        else
+	            {
+	            LOG_WRITE_L("No SOAP fault was received.");
+	            aConsumer.HandleErrorL(NULL, aErrorCode, aTxnId, aResponseTransportProperties);
+	            retVal = KErrSenInternal;
+	            }
+	   		CleanupStack::PopAndDestroy( apSOAPMessage ); 
+        }
+		
+		
+                
+    return retVal;
+    }
+TInt CSenBasicWebServiceSession::HandleSoapFaultL(CSenSoapMessage* apSOAPMessage,
+                                            HBufC8*& aResponse)
+{
+	return(CSenWebServiceSession::HandleSoapFaultL(apSOAPMessage,aResponse));
+}
+
+//  End of File