/**************************************************************** ** Licensed Materials - Property of IBM ** ** IBM Cognos Products: mdsrv ** ** (C) Copyright IBM Corp. 2008, 2010 ** ** US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. *****************************************************************/ /** * This class allows for the sending of an async request to the Cognos BI Bus. * * @constructor * @extends C_SoapRequest * @extends I_ServerPromptingListener * @extends I_ServerLogonListener * @requires G_BusServer * @requires C_Error * @param {I_RequestListener} v_oListener The listener for this request. If null, then no events will be fired. * @param {String} v_sSOAPAction SOAP action to set in the request header * @param {String} v_sRequest Request to send in SOAP body */ function C_mdsrvBusRequest( v_oListener, v_sSOAPAction, v_sRequest ) { this.F_ConstructBaseClass( v_oListener, G_CCHL.M_sGatewayURL, v_sSOAPAction ); /** * @private */ this.m_sRequest = v_sRequest; /** * @private */ this.m_sRequestSoapAction = v_sSOAPAction; /** * @private */ this.m_docResponse = null; /** * @private */ this.m_bProcessResponse = true; /** * @private */ this.m_bServerPrompting = true; /** * @private */ this.m_sPromptReport = ""; /** * @private */ this.m_bAsyncBusRequest = false; /** * @private */ this.m_sRoutingServerGroup = null; /** * @private */ this.m_bIsLoggingOn = false; /** * @private */ this.m_bIsPrompting = false; /** * @private */ this.m_sFollowOnRequestSOAPAction = C_mdsrvBusRequest.K_sSOAPAction_metadataService_absolute; /** * @private */ this.m_sCancelRequestSOAPAction = C_mdsrvBusRequest.K_sSOAPAction_metadataService_control; /** * @private */ this.m_aNamespaces = []; this.F_AddNamespace( C_mdsrvBusRequest.k_sBIBusNamespaceDecl ); this.F_AddNamespace( C_mdsrvBusRequest.k_sBIBusMDNamespaceDecl ); }; C_mdsrvBusRequest.F_Extends( C_SoapRequest ); /** * Primary Wait Threshold to use for async requests * @type Integer */ C_mdsrvBusRequest.K_sPrimaryWaitThreshold = 50; /** * Secondary Wait Threshold to use for async requests * @type Integer */ C_mdsrvBusRequest.K_sSecondaryWaitThreshold = 30; /** * @private */ C_mdsrvBusRequest.m_sLastRequest = ""; /** * @private */ C_mdsrvBusRequest.m_sLastResponse = ""; /** * Holds the available bus tracking info available for a new request. Only one request at a * time can be using a given bus:tracking * * @private */ C_mdsrvBusRequest.m_aBusTracking = []; /** * @returns The last SOAP request sent to the server. * @type String */ C_mdsrvBusRequest.F_GetLastRequest = function() { return this.m_sLastRequest; }; /** * @returns The last SOAP response returned by the server. * @type XMLDocument */ C_mdsrvBusRequest.F_GetLastResponse = function() { return this.m_sLastResponse; }; /** * Releases all current conversations being maintained with the server thereby allowing the server * to free the resources asssociated with them. * @type void */ C_mdsrvBusRequest.F_ReleaseAllTracking = function() { // This method will only release reportService conversations. A more general approach will be // needed in the future to release the requests associated with each service. // We will need to have global objects to manage the requests RS makes to each service so that the // conversations, and async activity can be managed properly. // I have logged " 593994 0 BUS requests are not managed properly" to track this var v_iRequests = this.m_aBusTracking.length; var v_sReleaseRequest = "" + '' + '' + ""; // release each bus request being maintained for (var i = 0; i < v_iRequests; ++i) { var v_oReleaseRequest = new C_mdsrvBusRequest( null, C_mdsrvBusRequest.K_sSOAPAction_metadataService_control, v_sReleaseRequest ); // Requests must be synchronous because they typically happen when the browser is shutting down. We abort all active requests when // shutting down the browser to ensure it goes down cleanly, so if these requests are async, they will be aborted before the server // gets them. v_oReleaseRequest.m_bAsync = false; v_oReleaseRequest.F_Send(); } }; /** * @returns The request SOAP response * @type XMLDocument */ C_mdsrvBusRequest.prototype.F_GetResponse = function() { return this.m_docResponse; }; /** * @returns True if the prompt window is up * @type Boolean */ C_mdsrvBusRequest.prototype.F_IsPrompting = function() { return this.m_bIsPrompting; }; /** * @returns True if the logon window is up * @type Boolean */ C_mdsrvBusRequest.prototype.F_IsLoggingOn = function() { return this.m_bIsLoggingOn; }; /** * Overrides the default CCHL locales for this request. * @param {String} v_sProductLocale Product locale. * @param {String} v_sContentLocale Content locale. * @type void */ C_mdsrvBusRequest.prototype.F_SetLocale = function(v_sProductLocale, v_sContentLocale) { this.m_sProductLocale = v_sProductLocale; this.m_sContentLocale = v_sContentLocale; }; /** * The response for the request will not be processed and checked for any errors or server interaction * @type void */ C_mdsrvBusRequest.prototype.F_SetNoResponseProcessing = function() { this.m_bProcessResponse = false; }; /** * Sets the request to not do server prompting. * @type void */ C_mdsrvBusRequest.prototype.F_SetNoServerPrompting = function() { this.m_bServerPrompting = false; }; /** * Sets the routing server group to use for this request. * @type void */ C_mdsrvBusRequest.prototype.F_SetRoutingServerGroup = function(v_sRoutingServerGroup) { this.m_sRoutingServerGroup = v_sRoutingServerGroup; }; /** * Sets the request to follow the BI Bus asynchronous mechanism * @type void */ C_mdsrvBusRequest.prototype.F_SetAsyncBusRequest = function(v_sWaitMethod, v_sCancelMethod, v_sGetOutputMethod, v_sFollowOnRequestSOAPAction, v_sCancelRequestSOAPAction) { this.m_bAsyncBusRequest = true; this.m_sWaitMethod = v_sWaitMethod; this.m_sCancelMethod = v_sCancelMethod; this.m_sGetOutputMethod = v_sGetOutputMethod; this.m_sFollowOnRequestSOAPAction = v_sFollowOnRequestSOAPAction ? v_sFollowOnRequestSOAPAction : this.m_sFollowOnRequestSOAPAction; this.m_sCancelRequestSOAPAction = v_sCancelRequestSOAPAction ? v_sCancelRequestSOAPAction : this.m_sCancelRequestSOAPAction; }; /** * @param {String} v_sPromptReport * @type void */ C_mdsrvBusRequest.prototype.F_SetPromptReport = function( v_sPromptReport ) { this.m_sPromptReport = v_sPromptReport; }; /** * Creates an object context that can be used for a request. * @returns A context object that can be used for a request. The content object contains an m_eType attribute. * @type Object */ C_mdsrvBusRequest.F_CreateContext = function(v_eType) { var v_oContext = {}; v_oContext.m_eType = v_eType; return v_oContext; }; /** * @type String */ C_mdsrvBusRequest.K_sSOAPAction_metadataService_high = "http://developer.cognos.com/schemas/metadataService/3.high"; /** * @type String */ C_mdsrvBusRequest.K_sSOAPAction_metadataService_absolute = "http://developer.cognos.com/schemas/metadataService/3.absolute"; /** * @type String */ C_mdsrvBusRequest.K_sSOAPAction_metadataService_session = "http://developer.cognos.com/schemas/metadataService/3.session"; /** * @type String */ C_mdsrvBusRequest.K_sSOAPAction_metadataService_control = "http://developer.cognos.com/schemas/metadataService/3.session"; /** * @type String */ C_mdsrvBusRequest.K_sSOAPAction_contentManagerService = "http://developer.cognos.com/schemas/bibus/3#contentManagerService"; //Based on FM Caspian RTC task 231966: MDSRV-SOAP ACTIONS - must amend for Planning bridging, //SOAP requests sent to Content Manager must look like this: http://www.ibm.com/xmlns/prod/cognos/contentManagerService/201109/. //So this C_mdsrvBusRequest.K_sSOAPAction_contentManagerService value has been out of date. //While global search shows it is used nowhere in mdsrv client. We should consider about remove this variable safely. /** * @type String */ C_mdsrvBusRequest.K_sSOAPAction_systemService = "http://developer.cognos.com/schemas/bibus/3#systemService"; C_mdsrvBusRequest.K_sSOAPAction_metadataService = "http://developer.cognos.com/schemas/bibus/3#metadataService"; /** * @private */ C_mdsrvBusRequest.k_sBIBusNamespace = "http://developer.cognos.com/schemas/bibus/3"; /** * @private */ C_mdsrvBusRequest.k_sBIBusNamespaceDecl = "xmlns:bus='" + C_mdsrvBusRequest.k_sBIBusNamespace + "/'"; /** * @private */ C_mdsrvBusRequest.k_sBIBusMDNamespaceDecl = "xmlns:md1='http://developer.cognos.com/schemas/metadataService/3'"; /** * @param {String} v_sNamespace * @type void */ C_mdsrvBusRequest.prototype.F_AddNamespace = function( v_sNamespace ) { this.m_aNamespaces.push( v_sNamespace ); }; /** * @type void */ C_mdsrvBusRequest.prototype.F_Send = function() { this.f_sendSoapRequest( this.f_createSoapRequest( this.m_sRequest, this.m_sProductLocale, this.m_sContentLocale ), this.m_sRequestSoapAction); }; /** * @private */ C_mdsrvBusRequest.prototype.f_sendSoapRequest = function(v_sSoapRequest, v_sSoapAction) { C_mdsrvBusRequest.m_sLastRequest = v_sSoapRequest; C_mdsrvBusRequest.m_sLastResponse = ""; this.F_SetSoapAction(v_sSoapAction); this.F_SetRequestBody(v_sSoapRequest); C_mdsrvBusRequest.superClass.F_Send.call( this ); }; /** * @protected */ C_mdsrvBusRequest.prototype.F_IsReadyToProcess = function() { if ( !C_mdsrvBusRequest.superClass.F_IsReadyToProcess.call( this ) ) { return false; } delete this.m_oFollowOnState; // Check if any errors happened in the web request. if ( this.F_GetError() ) { // allow the request to continue processing return !this.m_bPendingAbort; } var v_sResponseText = this.F_GetResponseText(); var v_docResponse = U_XML.F_LoadString( null, v_sResponseText, false, true ); this.m_docResponse = v_docResponse; if ( !v_docResponse || !v_docResponse.documentElement) { return !this.m_bPendingAbort; } this.m_docResponse.setProperty( "SelectionNamespaces", "xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' " + this.m_aNamespaces.join( " " ) ); C_mdsrvBusRequest.m_sLastResponse = v_docResponse.xml; var v_nFault = v_docResponse.selectSingleNode( '/SOAP-ENV:Envelope/SOAP-ENV:Body/SOAP-ENV:Fault' ); if ( v_nFault && !this.m_bPendingAbort ) { if (this.m_bServerPrompting && this.m_oListener && G_BusServer.F_AuthenticationRequired(v_docResponse)) { this.m_bLoggingOn = true; //G_App.F_ShowXMLTree( v_docResponse, "Logon prompt response" ); if (G_BusServer.F_Logon(this, v_docResponse)) { // Depending on what happens after logon, either the request will be completed (failed) // or it will be re-executed delete this.m_docResponse; return false; } this.m_bLoggingOn = false; this.F_SetNewErrorRes( "IDS_CCHL_INITIATE_LOGON_FAILED" ); } return true; } var v_nBusTracking = v_docResponse.selectSingleNode('/SOAP-ENV:Envelope/SOAP-ENV:Header/bus:biBusHeader/bus:tracking'); if (v_nBusTracking) { var v_sBusTracking = v_nBusTracking.xml; if (this.m_bPendingAbort) { this.m_bPendingAbort = false; var v_bCancellable = (v_docResponse.selectSingleNode( "/SOAP-ENV:Envelope/SOAP-ENV:Body/*/bus:result[bus:status='working' or bus:status='stillWorking']" ) != null); this.m_oFollowOnState = this.f_createFollowOnState(v_docResponse, v_sBusTracking, v_bCancellable); this.F_Abort(); return false; } // If there were no errors, then we can reuse the tracking // Make tracking available for resuse in subsequent requests. // If this request resubmits itself, then it should reuse the same tracking because it will be at the // top of the queue. C_mdsrvBusRequest.m_aBusTracking.push(v_sBusTracking); // An async method requires tracking to work correctly if (this.m_bAsyncBusRequest) { if (v_docResponse.selectSingleNode( "/SOAP-ENV:Envelope/SOAP-ENV:Body/*/bus:result[bus:status='complete'][bus:details/item/bus:status='responseReady']" ) ) { delete this.m_docResponse; this.f_sendFollowOnRequest(this.m_sGetOutputMethod, v_docResponse, v_sBusTracking, false); return false; } else if (v_docResponse.selectSingleNode( "/SOAP-ENV:Envelope/SOAP-ENV:Body/*/bus:result[bus:status='working' or bus:status='stillWorking']" ) ) { delete this.m_docResponse; this.f_sendFollowOnRequest(this.m_sWaitMethod, v_docResponse, v_sBusTracking, true); return false; } } } if (this.m_bPendingAbort) { // If the bus:tracking info is missing, then it is not possible to cancel this on the server this.f_forcePendingAbortOnClient(); return false; } if (this.m_bServerPrompting && this.m_oListener && G_BusServer.F_RequiresServerPrompting(v_docResponse)) { this.m_bIsPrompting = true; if (G_BusServer.F_DoPrompting(this, v_docResponse, this.m_sPromptReport)) { // Depending on what happens after prompting, either the request will be completed (failed) // or it will be re-executed delete this.m_docResponse; return false; } this.m_bIsPrompting = false; this.F_SetNewErrorRes( "IDS_CCHL_INITIATE_SERVERPROMTING_FAILED" ); return true; } return true; }; /** * @protected */ C_mdsrvBusRequest.prototype.F_ProcessResponse = function() { C_mdsrvBusRequest.superClass.F_ProcessResponse.call( this ); if ( this.F_GetError() ) { this.m_docResponse = null; return; } if (this.m_docResponse && this.m_docResponse.documentElement) { var v_nFault = this.m_docResponse.selectSingleNode( '/SOAP-ENV:Envelope/SOAP-ENV:Body/SOAP-ENV:Fault' ); if ( v_nFault ) { this.F_SetError( new C_BusSoapFault( this.m_docResponse ) ); this.m_docResponse = null; } } else { var v_aMsg = []; var v_sResponseText = this.F_GetResponseText(); if ( v_sResponseText ) { v_aMsg.push( v_sResponseText ); } else { v_aMsg.push(G_ResManager.F_GetString( "IDS_CCHL_HTTP_UNKNOWN_RESPONSE")); v_aMsg.push("\r\n"); // These strings are hard coded, they are a last resort when there are problems. v_aMsg.push("Gateway URL: " + G_CCHL.M_sGatewayURL); v_aMsg.push("Document URL: " + document.URL); var v_sStatusText = this.F_GetStatusText(); if ( v_sStatusText ) { v_aMsg.push("HTTP Status Text: " + v_sStatusText); } } this.m_docResponse = null; this.F_SetNewErrorRes( "IDS_CCHL_XMLHTTPERROR", v_aMsg.join( "\r\n" ) ); } }; /** * @protected */ C_mdsrvBusRequest.prototype.f_sendFollowOnRequest = function(v_sMethod, v_docResponse, v_sBusTracking, v_bCancellable) { G_Debug.F_Print("C_mdsrvBusRequest.f_sendFollowOnRequest : " + v_sMethod); this.m_oFollowOnState = this.f_createFollowOnState(v_docResponse, v_sBusTracking, v_bCancellable); var v_sRequest = "<" + v_sMethod + ">" + '' + this.m_oFollowOnState.m_sConversation + '' + '' + '' + ""; this.f_sendSoapRequest(this.f_createSoapRequest( v_sRequest, this.m_sProductLocale, this.m_sContentLocale ), this.m_sFollowOnRequestSOAPAction); }; /** * Abort the current request. * @type void */ C_mdsrvBusRequest.prototype.F_Abort = function() { if (this.m_bAsyncBusRequest && !this.m_oFollowOnState && !this.m_bCompleted) { G_Debug.F_Print("C_mdsrvBusRequest pending abort"); /** * @private */ this.m_bPendingAbort = true; // Force pending abort on the client after 10 seconds var v_oRequest = this; setTimeout(function() { v_oRequest.f_forcePendingAbortOnClient() }, 10000); if ( this.m_oListener && this.m_oListener.F_Request_OnAborted ) { this.m_oListener.F_Request_OnAborted( this ); } return; } C_mdsrvBusRequest.superClass.F_Abort.call( this ); if (this.m_oFollowOnState && this.m_oFollowOnState.m_bCancellable) { this.f_cancelRequest(); } }; /** * @private * This method forces the client to abort the request. This is done to ensure that the browser client connections * do not get locked up waiting for a server response for cancel. */ C_mdsrvBusRequest.prototype.f_forcePendingAbortOnClient = function() { if (this.m_bPendingAbort) { G_Debug.F_Print("C_mdsrvBusRequest pending abort forced on client"); this.m_bCompleted = true; // ensures F_Abort does not fire the OnAbort event since it has already been fired. this.m_bPendingAbort = false; C_mdsrvBusRequest.superClass.F_Abort.call( this ); } }; /** * @private */ C_mdsrvBusRequest.prototype.f_createFollowOnState = function(v_docResponse, v_sBusTracking, v_bCancellable) { var v_aConversation = []; var nl = v_docResponse.selectNodes( "/SOAP-ENV:Envelope/SOAP-ENV:Body/*/bus:result/bus:primaryRequest/*" ); for ( var i = 0; i < nl.length; i++ ) { v_aConversation.push(nl.item( i ).xml); } var v_sConversation = v_aConversation.join(""); var v_oCancelState = { "m_sConversation" : v_sConversation, "m_sBusTracking" : v_sBusTracking, "m_bCancellable" : v_bCancellable }; return v_oCancelState; }; /** * @private */ C_mdsrvBusRequest.prototype.f_cancelRequest = function() { G_Debug.F_Print("C_mdsrvBusRequest cancelling request on server"); var v_sCancelConversation = this.m_oFollowOnState.m_sConversation; var v_sCancelBusTracking = this.m_oFollowOnState.m_sBusTracking; delete this.m_oFollowOnState; C_mdsrvBusRequest.m_aBusTracking.push(v_sCancelBusTracking); var v_sCancelRequest = "<" + this.m_sCancelMethod + ">" + '' + v_sCancelConversation + '' + ""; var v_oCancelRequest = new C_mdsrvBusRequest( null, this.m_sCancelRequestSOAPAction, v_sCancelRequest ); v_oCancelRequest.F_Send(); }; /** * @param {Boolean} v_bSuccess * @type void */ C_mdsrvBusRequest.prototype.F_OnServerLogonComplete = function(v_bSuccess) { this.m_bIsLoggingOn = false; // if logon successful if (G_BusServer.F_GetPassport() && v_bSuccess ) { this.F_Send(); return; } this.F_SetNewErrorRes( "IDS_CCHL_REQUEST_CANCELLED_LOGON" ); this.m_docResponse = null; this.m_oListener.F_Request_OnComplete(this); }; /** * @type void */ C_mdsrvBusRequest.prototype.F_OnServerPromptingComplete = function() { this.m_bIsPrompting = false; // if prompting was successful if (G_BusServer.F_HasParameterValues()) { // take existing request and replace parameters with the new ones var v_sRequest = this.m_sRequest; var v_idxStartParams = v_sRequest.indexOf( "" ); if ( v_idxStartParams != - 1 && v_idxEndParams != -1 ) { v_sRequest = v_sRequest.substring(0, v_idxStartParams) + G_BusServer.F_GetParameterValues() + v_sRequest.substring(v_idxEndParams + 22); } else if ( v_idxStartParams != - 1 && v_idxEndParams == -1 ) { v_sParamsStart = v_sRequest.slice( v_idxStartParams ); v_idxEndParams = v_sParamsStart.indexOf( "/>" ); v_sRequest = v_sRequest.substring(0, v_idxStartParams) + G_BusServer.F_GetParameterValues() + v_sRequest.substring(v_idxStartParams + v_idxEndParams + 2); } else { G_Debug.F_Alert('Could not replace params in request'); } this.m_sRequest = v_sRequest; this.F_Send(); return; } this.F_SetNewErrorRes( "IDS_CCHL_REQUEST_CANCELLED_PROMPTING" ); this.m_docResponse = null; this.m_oListener.F_Request_OnComplete(this); }; /** * @private */ C_mdsrvBusRequest.prototype.f_createSoapRequest = function( v_sRequest, v_sProductLocale, v_sContentLocale ) { var v_sPassport = G_BusServer.F_GetPassport(); var v_sRouterServerGroup = (this.m_sRoutingServerGroup === null) ? G_BusServer.F_GetRoutingServerGroup() : this.m_sRoutingServerGroup; var v_sCafContextId = G_BusServer.F_GetCafContextId(); var v_sBusTracking = (C_mdsrvBusRequest.m_aBusTracking.length > 0) ? C_mdsrvBusRequest.m_aBusTracking.pop() : ""; var v_sSOAPRequest = '' + '' + '' + ( v_sPassport ? ('' + '' + '' + v_sPassport + '' + '' + '' + G_BusServer.F_GetAuthenticityToken() + '' + '') : '' ) + ( v_sCafContextId ? ('' + '' + v_sCafContextId + '' + '') : '' ) + '' + '' + 'productLocale' + '' + (v_sProductLocale ? v_sProductLocale : G_CCHL.M_sProductLocale) + '' + '' + '' + 'contentLocale' + '' + (v_sContentLocale ? v_sContentLocale : G_CCHL.M_sContentLocale) + '' + '' + '' + '' + '' + 'md' + 'true' + '' + '' + v_sBusTracking + ( v_sRouterServerGroup ? ('' + '' + v_sRouterServerGroup + '' + '') : '' ) + '' + '' + '' + v_sRequest + '' + ''; return v_sSOAPRequest; }; /** * This class is used to capture the error contained in a BUS SOAP fault. * * @constructor * @extends I_Error * @param {XMLDocument} v_docSoapResponse */ function C_BusSoapFault(v_docSoapResponse) { /** * @private */ this.m_sErrorSummary = ""; /** * @private */ this.m_sErrorDetails = ""; /** * @private */ this.m_sErrorCode = ""; v_docSoapResponse.setProperty( "SelectionNamespaces", "xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' " + C_mdsrvBusRequest.k_sBIBusNamespaceDecl ); // Search the document since this class is also used for documents that are not // complete SOAP responses. var v_nFault = v_docSoapResponse.selectSingleNode('//SOAP-ENV:Fault'); var nl = v_nFault.selectNodes(".//bus:messageString | .//messageString | .//bus:message[not(*)] | .//message[not(*)]"); if (nl.length > 0) { var v_sMsg = nl.item(0).text; var i = v_sMsg.indexOf(" "); this.m_sErrorSummary = ( i > 0 ) ? v_sMsg.substring( i + 1 ) : v_sMsg; this.m_sErrorCode = ( i > 0 ) ? v_sMsg.substring( 0, i ) : ""; var v_aDetails = []; for (var j = 1; j < nl.length; ++j) { v_aDetails.push(nl.item(j).text); } this.m_sErrorDetails = v_aDetails.join("\r\n"); } else { var v_nFaultString = v_nFault.selectSingleNode("faultstring | SOAP-ENV:faultstring"); if (v_nFaultString) { this.m_sErrorSummary = v_nFaultString.text; } var v_nFaultCode = v_nFault.selectSingleNode("faultcode | SOAP-ENV:faultcode"); if (v_nFaultCode) { this.m_sErrorCode = v_nFaultCode.text; } } if (!this.m_sErrorSummary) { this.m_sErrorSummary = G_ResManager.F_GetString("IDS_CCHL_UNRECOGNIZED_SOAP_FAULT"); this.m_sErrorDetails = v_nFault.xml; } }; /** * @type String */ C_BusSoapFault.prototype.F_GetErrorSummary = function() { return this.m_sErrorSummary; }; /** * @type String */ C_BusSoapFault.prototype.F_GetErrorDetails = function() { return this.m_sErrorDetails; }; /** * @type String */ C_BusSoapFault.prototype.F_GetErrorCode = function() { return this.m_sErrorCode; };