Back to index

lightning-sunbird  0.9+nobinonly
wspcallcontext.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2001
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Vidur Apparao (vidur@netscape.com)  (Original author)
00024  *   John Bandhauer (jband@netscape.com)
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "wspprivate.h"
00041 #include "nsIVariant.h"
00042 #include "nsIWSDL.h"
00043 #include "nsISOAPCall.h"
00044 #include "nsISOAPHeaderBlock.h"
00045 #include "nsISOAPParameter.h"
00046 #include "nsIWSDLSOAPBinding.h"
00047 
00048 WSPCallContext::WSPCallContext(WSPProxy* aProxy, nsISOAPCall* aSOAPCall,
00049                                const nsAString& aMethodName,
00050                                nsIWSDLOperation* aOperation)
00051   : mProxy(aProxy), mCall(aSOAPCall), mMethodName(aMethodName),
00052     mOperation(aOperation), mStatus(NS_ERROR_NOT_AVAILABLE)
00053 {
00054   NS_IF_ADDREF(mProxy);
00055 }
00056 
00057 WSPCallContext::~WSPCallContext()
00058 {
00059   NS_IF_RELEASE(mProxy);
00060 }
00061 
00062 NS_IMPL_ISUPPORTS3_CI(WSPCallContext,
00063                       nsIWebServiceCallContext,
00064                       nsIWebServiceSOAPCallContext,
00065                       nsISOAPResponseListener)
00066 
00067 /* readonly attribute nsIWebServiceProxy proxy; */
00068 NS_IMETHODIMP
00069 WSPCallContext::GetProxy(nsIWebServiceProxy * *aProxy)
00070 {
00071   NS_ENSURE_ARG_POINTER(aProxy);
00072 
00073   *aProxy = mProxy;
00074   NS_IF_ADDREF(*aProxy);
00075 
00076   return NS_OK;
00077 }
00078 
00079 /* readonly attribute AString methodName; */
00080 NS_IMETHODIMP
00081 WSPCallContext::GetMethodName(nsAString & aMethodName)
00082 {
00083   aMethodName.Assign(mMethodName);
00084   return NS_OK;
00085 }
00086 
00087 /* readonly attribute PRUint32 status; */
00088 NS_IMETHODIMP
00089 WSPCallContext::GetStatus(PRUint32 *aStatus)
00090 {
00091   NS_ENSURE_ARG_POINTER(aStatus);
00092   *aStatus = mStatus;
00093   return NS_OK;
00094 }
00095 
00096 /* readonly attribute nsIException pendingException; */
00097 NS_IMETHODIMP
00098 WSPCallContext::GetPendingException(nsIException * *aPendingException)
00099 {
00100   NS_ENSURE_ARG_POINTER(aPendingException);
00101   *aPendingException = mException;
00102   NS_IF_ADDREF(*aPendingException);
00103   return NS_OK;
00104 }
00105 
00106 /* readonly attribute nsIWSDLOperation operation; */
00107 NS_IMETHODIMP
00108 WSPCallContext::GetOperation(nsIWSDLOperation * *aOperation)
00109 {
00110   NS_ENSURE_ARG_POINTER(aOperation);
00111   *aOperation = mOperation;
00112   NS_IF_ADDREF(*aOperation);
00113   return NS_OK;
00114 }
00115 
00116 /* void abort (in nsIException error); */
00117 NS_IMETHODIMP
00118 WSPCallContext::Abort(nsIException *error)
00119 {
00120   nsresult rv = NS_OK;
00121   if (mCompletion) {
00122     mException = error;
00123     PRBool ret;
00124     rv = mCompletion->Abort(&ret);
00125     if (NS_SUCCEEDED(rv) && ret) {
00126       rv = CallCompletionListener();
00127     }
00128     // Drop our ref to the completion object to break our cycle with
00129     // it.
00130     mCompletion = nsnull;
00131   }
00132   return rv;
00133 }
00134 
00135 /* readonly attribute nsISOAPResponse soapResponse; */
00136 NS_IMETHODIMP
00137 WSPCallContext::GetSoapResponse(nsISOAPResponse * *aSoapResponse)
00138 {
00139   NS_ENSURE_ARG_POINTER(aSoapResponse);
00140   NS_IF_ADDREF(*aSoapResponse = mResponse);
00141   return NS_OK;
00142 }
00143 
00144 /* boolean handleResponse (in nsISOAPResponse aResponse, in
00145    nsISOAPCall aCall, in nsresult status, in boolean aLast); */
00146 NS_IMETHODIMP
00147 WSPCallContext::HandleResponse(nsISOAPResponse *aResponse, nsISOAPCall *aCall,
00148                                nsresult status, PRBool aLast, PRBool *_retval)
00149 {
00150   NS_ASSERTION(aCall == mCall, "unexpected call instance");
00151   NS_ASSERTION(aLast, "only single response expected");
00152   mStatus = status;
00153   *_retval = PR_TRUE;
00154   CallCompletionListener();
00155   // Drop our ref to the completion object now that we dont need it.
00156   // This breaks our reference cycle with it and prevents leaks.
00157   mCompletion = nsnull;
00158   return NS_OK;
00159 }
00160 
00161 nsresult
00162 WSPCallContext::CallAsync(PRUint32 aListenerMethodIndex,
00163                           nsISupports* aListener)
00164 {
00165   mAsyncListener = aListener;
00166   mListenerMethodIndex = aListenerMethodIndex;
00167   return mCall->AsyncInvoke(this, getter_AddRefs(mCompletion));
00168 }
00169 
00170 nsresult
00171 WSPCallContext::CallSync(PRUint32 aMethodIndex, nsXPTCMiniVariant* params)
00172 {
00173   return mCall->Invoke(getter_AddRefs(mResponse));
00174 }
00175 
00176 nsresult
00177 WSPCallContext::CallCompletionListener()
00178 {
00179   nsresult rv;
00180 #define PARAM_BUFFER_COUNT     8  /* Never set less than 2 */
00181 
00182   if (!mProxy) {
00183     NS_ERROR("Huh, no proxy?");
00184 
00185     return NS_OK;
00186   }
00187   nsXPTCVariant paramBuffer[PARAM_BUFFER_COUNT];
00188   nsXPTCVariant* dispatchParams = nsnull;
00189 
00190   nsCOMPtr<nsISOAPFault> fault;
00191   mCompletion->GetResponse(getter_AddRefs(mResponse));
00192   if (mResponse) {
00193     rv = mResponse->GetFault(getter_AddRefs(fault));
00194     if (NS_FAILED(rv)) {
00195       return rv;
00196     }
00197   }
00198   if (!mResponse || fault) {
00199     WSPException* exception = new WSPException(fault, mStatus);
00200     if (!exception) {
00201       return NS_ERROR_OUT_OF_MEMORY;
00202     }
00203     mException = exception;
00204   }
00205 
00206   nsCOMPtr<nsIInterfaceInfo> listenerInterfaceInfo;
00207   mProxy->GetListenerInterfaceInfo(getter_AddRefs(listenerInterfaceInfo));
00208   NS_ASSERTION(listenerInterfaceInfo,
00209                "WSPCallContext:Missing listener interface info");
00210 
00211   const nsXPTMethodInfo* methodInfo;
00212   rv = listenerInterfaceInfo->GetMethodInfo(mListenerMethodIndex,
00213                                             &methodInfo);
00214   if (NS_FAILED(rv)) {
00215     return rv;
00216   }
00217 
00218   PRUint32 paramCount = methodInfo->GetParamCount();
00219   if(paramCount > PARAM_BUFFER_COUNT) {
00220     if(!(dispatchParams = new nsXPTCVariant[paramCount])) {
00221       return NS_ERROR_OUT_OF_MEMORY;
00222     }
00223   }
00224   else {
00225     dispatchParams = paramBuffer;
00226   }
00227 
00228   // iterate through the params to clear flags
00229   PRUint32 i;
00230   for(i = 0; i < paramCount; i++) {
00231     nsXPTCVariant* dp = &dispatchParams[i];
00232     dp->ClearFlags();
00233     dp->val.p = nsnull;
00234   }
00235 
00236   PRUint32 headerCount = 0, bodyCount = 0;
00237   nsISOAPHeaderBlock** headerBlocks;
00238   nsISOAPParameter** bodyBlocks;
00239 
00240 #define STRING_ARRAY_BUF_SIZE 2
00241   nsAutoString string_array_buf[STRING_ARRAY_BUF_SIZE];
00242   nsAutoString *string_array = &string_array_buf[0];
00243   PRUint32 string_array_index = 0;
00244 
00245 
00246   // If we have an exception, report it now
00247   if (mException) {
00248     nsCOMPtr<nsISupports> canonical_this = 
00249       do_QueryInterface(NS_STATIC_CAST(nsIWebServiceCallContext*, this));
00250     dispatchParams[0].val.p = mException.get();
00251     dispatchParams[0].SetValIsInterface();
00252     dispatchParams[0].type.flags = XPT_TDP_POINTER | TD_INTERFACE_TYPE;
00253 
00254     dispatchParams[1].val.p = canonical_this;
00255     dispatchParams[1].SetValIsInterface();
00256     dispatchParams[1].type.flags = XPT_TDP_POINTER | TD_INTERFACE_TYPE;
00257 
00258     rv = XPTC_InvokeByIndex(mAsyncListener, 3, 2, dispatchParams);
00259   }
00260   else if (mResponse) {
00261     nsCOMPtr<nsIWSDLBinding> binding;
00262     rv = mOperation->GetBinding(getter_AddRefs(binding));
00263     if (NS_FAILED(rv)) {
00264       goto call_completion_end;
00265     }
00266 
00267     nsCOMPtr<nsISOAPOperationBinding> operationBinding =
00268       do_QueryInterface(binding, &rv);
00269     if (NS_FAILED(rv)) {
00270       goto call_completion_end;
00271     }
00272 
00273     PRUint16 style;
00274     operationBinding->GetStyle(&style);
00275 
00276     rv = mResponse->GetHeaderBlocks(&headerCount, &headerBlocks);
00277     if (NS_FAILED(rv)) {
00278       goto call_completion_end;
00279     }
00280     rv = mResponse->GetParameters(style == nsISOAPPortBinding::STYLE_DOCUMENT,
00281                                   &bodyCount, &bodyBlocks);
00282     if (NS_FAILED(rv)) {
00283       goto call_completion_end;
00284     }
00285 
00286     nsCOMPtr<nsIWSDLMessage> output;
00287     rv = mOperation->GetOutput(getter_AddRefs(output));
00288     if (NS_FAILED(rv)) {
00289       goto call_completion_end;
00290     }
00291     PRUint32 partCount;
00292     output->GetPartCount(&partCount);
00293 
00294     PRUint32 maxParamIndex = methodInfo->GetParamCount()-1;
00295 
00296     PRUint32 bodyEntry = 0, headerEntry = 0, paramIndex = 0;
00297     for (i = 0; i < partCount; paramIndex++, i++) {
00298       nsCOMPtr<nsIWSDLPart> part;
00299       rv = output->GetPart(i, getter_AddRefs(part));
00300       if (NS_FAILED(rv)) {
00301         goto call_completion_end;
00302       }
00303       rv = part->GetBinding(getter_AddRefs(binding));
00304       if (NS_FAILED(rv)) {
00305         goto call_completion_end;
00306       }
00307 
00308       nsCOMPtr<nsISOAPPartBinding> partBinding =
00309         do_QueryInterface(binding, &rv);
00310       if (NS_FAILED(rv)) {
00311         goto call_completion_end;
00312       }
00313 
00314       PRUint16 location;
00315       partBinding->GetLocation(&location);
00316 
00317       nsCOMPtr<nsISOAPBlock> block;
00318       if (location == nsISOAPPartBinding::LOCATION_HEADER && 
00319           headerEntry < headerCount) {
00320         block = do_QueryInterface(headerBlocks[headerEntry++]);
00321       }
00322       else if (location == nsISOAPPartBinding::LOCATION_BODY &&
00323                bodyEntry < bodyCount) {
00324         block = do_QueryInterface(bodyBlocks[bodyEntry++]);
00325       }
00326 
00327       if (!block) {
00328         rv = NS_ERROR_UNEXPECTED;
00329         goto call_completion_end;
00330       }
00331 
00332       nsCOMPtr<nsISchemaComponent> schemaComponent;
00333       rv = part->GetSchemaComponent(getter_AddRefs(schemaComponent));
00334       if (NS_FAILED(rv)) {
00335         goto call_completion_end;
00336       }
00337 
00338       nsCOMPtr<nsISchemaType> type;
00339       nsCOMPtr<nsISchemaElement> element = do_QueryInterface(schemaComponent);
00340       if (element) {
00341         rv = element->GetType(getter_AddRefs(type));
00342         if (NS_FAILED(rv)) {
00343           goto call_completion_end;
00344         }
00345       }
00346       else {
00347         type = do_QueryInterface(schemaComponent);
00348       }
00349 
00350       rv = block->SetSchemaType(type);
00351       if (NS_FAILED(rv)) {
00352         goto call_completion_end;
00353       }
00354 
00355       nsCOMPtr<nsIVariant> value;
00356       rv = block->GetValue(getter_AddRefs(value));
00357       if (NS_FAILED(rv) || !value) {
00358         goto call_completion_end;
00359       }
00360 
00361       nsXPTCVariant* vars = dispatchParams + paramIndex;
00362 
00363       if (paramIndex < maxParamIndex &&
00364           methodInfo->GetParam((PRUint8)(paramIndex+1)).GetType().IsArray()) {
00365         paramIndex++;
00366       }
00367 
00368       NS_ASSERTION(paramIndex <= maxParamIndex,
00369                    "WSDL/IInfo param count mismatch");
00370 
00371       const nsXPTParamInfo& paramInfo = methodInfo->GetParam(paramIndex);
00372       
00373       if (XPT_TDP_TAG(paramInfo.type.prefix) == TD_DOMSTRING) {
00374         // If there's no more room in the string buffer on the stack
00375         // for this parameter, allocate an array on the heap.
00376         if (string_array == &string_array_buf[0] &&
00377             string_array_index >= STRING_ARRAY_BUF_SIZE) {
00378           string_array = new nsAutoString[partCount - i];
00379 
00380           if (!string_array) {
00381             rv = NS_ERROR_OUT_OF_MEMORY;
00382 
00383             goto call_completion_end;
00384           }
00385 
00386           // Reset string_array_index now that we switched arrays.
00387           string_array_index = 0;
00388         }
00389 
00390         // Give the variant value a nsAString object to hold the data
00391         // in.
00392         vars->val.p =
00393           NS_STATIC_CAST(nsAString *, &string_array[string_array_index++]);
00394       }
00395 
00396       rv = WSPProxy::VariantToInParameter(listenerInterfaceInfo,
00397                                           mListenerMethodIndex, &paramInfo,
00398                                           value, vars);
00399       if (NS_FAILED(rv)) {
00400         goto call_completion_end;
00401       }
00402     }
00403 
00404     NS_ASSERTION(paramIndex == maxParamIndex,
00405                  "WSDL/IInfo param count mismatch");
00406 
00407     dispatchParams[paramIndex].val.p =
00408         NS_STATIC_CAST(nsIWebServiceCallContext*, this);
00409     dispatchParams[paramIndex].SetValIsInterface();
00410     dispatchParams[paramIndex].type.flags = 
00411       XPT_TDP_POINTER | TD_INTERFACE_TYPE;
00412 
00413     rv = XPTC_InvokeByIndex(mAsyncListener, mListenerMethodIndex,
00414                             paramCount, dispatchParams);
00415   }
00416   else {
00417     rv = NS_ERROR_FAILURE;
00418   }
00419 
00420 call_completion_end:
00421   if (headerCount) {
00422     NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(headerCount, headerBlocks);
00423   }
00424   if (bodyCount) {
00425     NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(bodyCount, bodyBlocks);
00426   }
00427   if(dispatchParams != paramBuffer) {
00428     delete [] dispatchParams;
00429   }
00430   if (string_array != &string_array_buf[0]) {
00431     delete [] string_array;
00432   }
00433 
00434   nsCOMPtr<nsIWebServiceCallContext> kungFuDeathGrip(this);
00435   mProxy->CallCompleted(this);
00436   NS_RELEASE(mProxy);
00437 
00438   return rv;
00439 }