Files
Mozilla/mozilla/extensions/webservices/proxy/src/wspproxy.cpp
cbiesinger%web.de 540aa06c74 270224 create nsIPropertyBag2 for easier getting of values from a propertybag
r=shaver sr=darin


git-svn-id: svn://10.0.0.236/trunk@170990 18797224-902f-48f8-a5cc-f745e15eee43
2005-03-22 18:16:53 +00:00

1352 lines
37 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vidur Apparao (vidur@netscape.com) (Original author)
* John Bandhauer (jband@netscape.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "wspprivate.h"
#include "nsAutoPtr.h"
#include "nsIWSDL.h"
#include "nsIWSDLSOAPBinding.h"
#include "nsISchema.h"
#include "nsISOAPParameter.h"
#include "nsISOAPHeaderBlock.h"
#include "nsISOAPEncoding.h"
#include "nsIComponentManager.h"
#include "nsIVariant.h"
#include "nsVoidArray.h"
#define NS_SOAP_1_1_ENCODING_NAMESPACE \
"http://schemas.xmlsoap.org/soap/encoding/"
#define NS_SOAP_1_2_ENCODING_NAMESPACE \
"http://www.w3.org/2001/09/soap-encoding"
WSPProxy::WSPProxy()
: mIID(nsnull)
{
}
WSPProxy::~WSPProxy()
{
}
NS_IMETHODIMP
WSPProxy::Init(nsIWSDLPort* aPort, nsIInterfaceInfo* aPrimaryInterface,
nsIInterfaceInfoManager* aInterfaceInfoManager,
const nsAString& aQualifier, PRBool aIsAsync)
{
NS_ENSURE_ARG(aPort);
NS_ENSURE_ARG(aPrimaryInterface);
mPort = aPort;
mPrimaryInterface = aPrimaryInterface;
mInterfaceInfoManager = aInterfaceInfoManager;
mPrimaryInterface->GetIIDShared(&mIID);
mQualifier.Assign(aQualifier);
mIsAsync = aIsAsync;
nsresult rv;
mInterfaces = do_CreateInstance(NS_SCRIPTABLE_INTERFACES_CONTRACTID, &rv);
if (!mInterfaces) {
return rv;
}
rv = mInterfaces->SetManager(mInterfaceInfoManager);
if (NS_FAILED(rv)) {
return rv;
}
if (mIsAsync) {
// Get the completion method info
const nsXPTMethodInfo* listenerGetter;
rv = mPrimaryInterface->GetMethodInfo(3, &listenerGetter);
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
const nsXPTParamInfo& listenerParam = listenerGetter->GetParam(0);
const nsXPTType& type = listenerParam.GetType();
if (!type.IsInterfacePointer()) {
return NS_ERROR_FAILURE;
}
rv = mPrimaryInterface->GetInfoForParam(3, &listenerParam,
getter_AddRefs(mListenerInterfaceInfo));
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
NS_METHOD
WSPProxy::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
{
NS_ENSURE_ARG_POINTER(aInstancePtr);
NS_ENSURE_NO_AGGREGATION(outer);
WSPProxy* proxy = new WSPProxy();
if (!proxy) {
return NS_ERROR_OUT_OF_MEMORY;
}
NS_ADDREF(proxy);
nsresult rv = proxy->QueryInterface(aIID, aInstancePtr);
NS_RELEASE(proxy);
return rv;
}
NS_IMPL_ADDREF(WSPProxy)
NS_IMPL_RELEASE(WSPProxy)
NS_IMETHODIMP
WSPProxy::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if((mIID && aIID.Equals(*mIID)) || aIID.Equals(NS_GET_IID(nsISupports))) {
*aInstancePtr = NS_STATIC_CAST(nsXPTCStubBase*, this);
NS_ADDREF_THIS();
return NS_OK;
}
else if (aIID.Equals(NS_GET_IID(nsIWebServiceProxy))) {
*aInstancePtr = NS_STATIC_CAST(nsIWebServiceProxy*, this);
NS_ADDREF_THIS();
return NS_OK;
}
else if (aIID.Equals(NS_GET_IID(nsIClassInfo))) {
*aInstancePtr = NS_STATIC_CAST(nsIClassInfo*, this);
NS_ADDREF_THIS();
return NS_OK;
}
return NS_ERROR_NO_INTERFACE;
}
///////////////////////////////////////////////////
//
// Implementation of nsXPTCStubBase methods
//
///////////////////////////////////////////////////
/**
* Asynchronous processing :
* 1-> WSPProxy::CallMethod
* 2 -> WSPCallContext::CallAsync
* 3 -> nsSOAPCall::AsyncInvoke
* 4 -> nsXXXSOAPTransport::AsyncCall
* 5 -> nsIXMLHttpRequest::Send, nsXXXSOAPTransportCompletion::AddEventListener
* ---- asynchronous ----
* 6 -> nsXXXSOAPTransportCompletion::HandleEvent
* 7 -> WSPCallContext::HandleResponse,
* WSPCallContext::CallCompletionListener
* 8 -> nsSOAPBlock::SetSchemaType, nsSOAPBlock::GetValue
* 9 -> nsSOAPEncoding::Decode, nsDefaultSOAPDecode::Decode
* 10 -> WSPProxy::CallCompleted
*/
NS_IMETHODIMP
WSPProxy::CallMethod(PRUint16 methodIndex,
const nsXPTMethodInfo* info,
nsXPTCMiniVariant* params)
{
nsresult rv;
nsCOMPtr<nsIWebServiceCallContext> cc;
nsCOMPtr<nsIWSDLBinding> binding;
if (methodIndex < 3) {
NS_ERROR("WSPProxy: bad method index");
return NS_ERROR_FAILURE;
}
// The first method in the interface for async callers is the
// one to set the async listener
if (mIsAsync && (methodIndex == 3)) {
nsISupports* listener = NS_STATIC_CAST(nsISupports*, params[0].val.p);
mAsyncListener = listener;
return NS_OK;
}
PRUint32 methodOffset;
if (mIsAsync) {
methodOffset = 4;
}
else {
methodOffset = 3;
}
nsCOMPtr<nsIWSDLOperation> operation;
rv = mPort->GetOperation(methodIndex - methodOffset,
getter_AddRefs(operation));
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsIWSDLMessage> input;
rv = operation->GetInput(getter_AddRefs(input));
if (NS_FAILED(rv)) {
return rv;
}
// Create the call instance
nsCOMPtr<nsISOAPCall> call = do_CreateInstance(NS_SOAPCALL_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsISOAPEncoding> encoding =
do_CreateInstance(NS_SOAPENCODING_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
return rv;
}
call->SetEncoding(encoding);
// Get the method name and target object uri
nsAutoString methodName, targetObjectURI;
rv = operation->GetBinding(getter_AddRefs(binding));
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsISOAPOperationBinding> operationBinding =
do_QueryInterface(binding, &rv);
if (NS_FAILED(rv)) {
return rv;
}
nsAutoString soapAction;
operationBinding->GetSoapAction(soapAction);
call->SetActionURI(soapAction);
PRUint16 style;
operationBinding->GetStyle(&style);
// If the style is RPC, find the method name and target object URI.
// If it is document-style, these are both left blank.
if (style == nsISOAPPortBinding::STYLE_RPC) {
operation->GetName(methodName);
rv = input->GetBinding(getter_AddRefs(binding));
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsISOAPMessageBinding> messageBinding =
do_QueryInterface(binding, &rv);
if (NS_FAILED(rv)) {
return rv;
}
messageBinding->GetNamespace(targetObjectURI);
}
// Set the transport URI
rv = mPort->GetBinding(getter_AddRefs(binding));
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsISOAPPortBinding> portBinding = do_QueryInterface(binding, &rv);
if (NS_FAILED(rv)) {
return rv;
}
nsAutoString address;
portBinding->GetAddress(address);
rv = call->SetTransportURI(address);
if (NS_FAILED(rv)) {
return rv;
}
PRUint16 version;
portBinding->GetSoapVersion(&version);
if (version == nsISOAPMessage::VERSION_UNKNOWN) {
version = nsISOAPMessage::VERSION_1_1;
}
// Set up the parameters to the call
PRUint32 i, partCount;
input->GetPartCount(&partCount);
PRUint32 maxParamIndex = info->GetParamCount()-1;
// Iterate through the parts to figure out how many are
// body vs. header blocks
nsCOMPtr<nsIWSDLPart> part;
PRUint32 headerCount = 0, bodyCount = 0;
for (i = 0; i < partCount; i++) {
rv = input->GetPart(i, getter_AddRefs(part));
if (NS_FAILED(rv)) {
return rv;
}
rv = part->GetBinding(getter_AddRefs(binding));
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsISOAPPartBinding> partBinding = do_QueryInterface(binding, &rv);
if (NS_FAILED(rv)) {
return rv;
}
PRUint16 location;
partBinding->GetLocation(&location);
if (location == nsISOAPPartBinding::LOCATION_HEADER) {
headerCount++;
}
else if (location == nsISOAPPartBinding::LOCATION_BODY) {
bodyCount++;
}
}
// Allocate parameter and header blocks
nsISOAPParameter** bodyBlocks = nsnull;
if (bodyCount) {
bodyBlocks = NS_STATIC_CAST(nsISOAPParameter**,
nsMemory::Alloc(bodyCount * sizeof(nsISOAPParameter*)));
if (!bodyBlocks) {
return NS_ERROR_OUT_OF_MEMORY;
}
for (i = 0; i < bodyCount; i++) {
rv = CallCreateInstance(NS_SOAPPARAMETER_CONTRACTID, &bodyBlocks[i]);
if (NS_FAILED(rv)) {
NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(i, bodyBlocks);
return rv;
}
}
}
nsISOAPHeaderBlock** headerBlocks = nsnull;
if (headerCount) {
headerBlocks = NS_STATIC_CAST(nsISOAPHeaderBlock**,
nsMemory::Alloc(headerCount * sizeof(nsISOAPHeaderBlock*)));
if (!headerBlocks) {
if (bodyBlocks) {
NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(bodyCount, bodyBlocks);
}
return NS_ERROR_OUT_OF_MEMORY;
}
for (i = 0; i < headerCount; i++) {
rv = CallCreateInstance(NS_SOAPHEADERBLOCK_CONTRACTID, &headerBlocks[i]);
if (NS_FAILED(rv)) {
if (bodyBlocks) {
NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(bodyCount, bodyBlocks);
}
NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(i, headerBlocks);
return rv;
}
}
}
// Now iterate through the parameters and set up the parameter blocks
PRUint32 bodyEntry = 0, headerEntry = 0, paramIndex = 0;
for (i = 0; i < partCount; paramIndex++, i++) {
input->GetPart(i, getter_AddRefs(part));
part->GetBinding(getter_AddRefs(binding));
nsCOMPtr<nsISOAPPartBinding> partBinding = do_QueryInterface(binding);
PRUint16 location;
partBinding->GetLocation(&location);
nsCOMPtr<nsISOAPBlock> block;
if (location == nsISOAPPartBinding::LOCATION_HEADER) {
block = do_QueryInterface(headerBlocks[headerEntry++]);
}
else if (location == nsISOAPPartBinding::LOCATION_BODY) {
block = do_QueryInterface(bodyBlocks[bodyEntry++]);
}
if (!block) {
rv = NS_ERROR_FAILURE;
goto call_method_end;
}
// Get the name, namespaceURI and type of the block based on
// information from the WSDL part. If the schema component
// associated with the part is an element, these values come
// from the schema description of the element. If it is a
// type, then the values are gathered from elsewhere.
nsCOMPtr<nsISchemaComponent> schemaComponent;
rv = part->GetSchemaComponent(getter_AddRefs(schemaComponent));
if (NS_FAILED(rv)) {
goto call_method_end;
}
nsCOMPtr<nsISchemaType> type;
nsAutoString blockName, blockNamespace;
nsCOMPtr<nsISchemaElement> element = do_QueryInterface(schemaComponent);
if (element) {
rv = element->GetType(getter_AddRefs(type));
if (NS_FAILED(rv)) {
goto call_method_end;
}
element->GetName(blockName);
element->GetTargetNamespace(blockNamespace);
}
else {
type = do_QueryInterface(schemaComponent);
nsAutoString paramName;
part->GetName(paramName);
blockName.Assign(paramName);
partBinding->GetNamespace(blockNamespace);
}
block->SetName(blockName);
block->SetNamespaceURI(blockNamespace);
block->SetSchemaType(type);
nsAutoString encodingStyle;
PRUint16 use;
partBinding->GetUse(&use);
// XXX Need a way to specify that a block should not be
// encoded.
if (use == nsISOAPPartBinding::USE_ENCODED) {
partBinding->GetEncodingStyle(encodingStyle);
if (!encodingStyle.IsEmpty()) {
nsCOMPtr<nsISOAPEncoding> partEncoding;
encoding->GetAssociatedEncoding(encodingStyle, PR_FALSE,
getter_AddRefs(partEncoding));
block->SetEncoding(partEncoding);
}
}
// Look ahead in the param info array to see if the current part has to be
// treated as an array. If so then get the array length from the current
// param and increment the param index.
PRUint32 arrayLength;
if (paramIndex < maxParamIndex &&
info->GetParam((PRUint8)(paramIndex + 1)).GetType().IsArray()) {
arrayLength = params[paramIndex++].val.u32;
}
else {
arrayLength = 0;
}
NS_ASSERTION(paramIndex <= maxParamIndex,
"WSDL/IInfo param count mismatch");
const nsXPTParamInfo& paramInfo = info->GetParam(paramIndex);
nsCOMPtr<nsIVariant> value;
rv = ParameterToVariant(mPrimaryInterface, methodIndex,
&paramInfo, params[paramIndex],
arrayLength, getter_AddRefs(value));
if (NS_FAILED(rv)) {
goto call_method_end;
}
block->SetValue(value);
}
// Encode the parameters to the call
rv = call->Encode(version,
methodName, targetObjectURI,
headerCount, headerBlocks,
bodyCount, bodyBlocks);
if (NS_FAILED(rv)) {
goto call_method_end;
}
WSPCallContext* ccInst;
ccInst = new WSPCallContext(this, call, methodName, operation);
if (!ccInst) {
rv = NS_ERROR_OUT_OF_MEMORY;
goto call_method_end;
}
cc = ccInst;
if (mIsAsync) {
PRUint8 pcount;
pcount = info->GetParamCount();
// There has to be at least one parameter - the retval.
if (pcount == 0) {
rv = NS_ERROR_FAILURE;
goto call_method_end;
}
#ifdef DEBUG
// The last one should be the retval.
const nsXPTParamInfo& retParamInfo = info->GetParam(pcount - 1);
if (!retParamInfo.IsRetval()) {
rv = NS_ERROR_FAILURE;
goto call_method_end;
}
// It should be an interface pointer
const nsXPTType& retType = retParamInfo.GetType();
if (!retType.IsInterfacePointer()) {
rv = NS_ERROR_FAILURE;
goto call_method_end;
}
#endif
nsIWebServiceCallContext** retval =
NS_STATIC_CAST(nsIWebServiceCallContext**, params[pcount-1].val.p);
if (!retval) {
rv = NS_ERROR_FAILURE;
goto call_method_end;
}
*retval = cc;
NS_ADDREF(*retval);
rv = ccInst->CallAsync(methodIndex, mAsyncListener);
if (NS_FAILED(rv)) {
goto call_method_end;
}
mPendingCalls.AppendObject(ccInst);
}
else {
rv = ccInst->CallSync(methodIndex, params);
}
call_method_end:
if (bodyBlocks) {
NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(bodyCount, bodyBlocks);
}
if (headerBlocks) {
NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(headerCount, headerBlocks);
}
return rv;
}
nsresult
WSPProxy::ParameterToVariant(nsIInterfaceInfo* aInterfaceInfo,
PRUint32 aMethodIndex,
const nsXPTParamInfo* aParamInfo,
nsXPTCMiniVariant aMiniVariant,
PRUint32 aArrayLength, nsIVariant** aVariant)
{
nsXPTType type;
nsresult rv = aInterfaceInfo->GetTypeForParam(aMethodIndex, aParamInfo,
0, &type);
if (NS_FAILED(rv)) {
return rv;
}
uint8 type_tag = type.TagPart();
nsCOMPtr<nsIInterfaceInfo> iinfo;
if (type.IsArray()) {
nsXPTType arrayType;
rv = aInterfaceInfo->GetTypeForParam(aMethodIndex, aParamInfo,
1, &arrayType);
if (NS_FAILED(rv)) {
return rv;
}
if (arrayType.IsInterfacePointer()) {
rv = aInterfaceInfo->GetInfoForParam(aMethodIndex, aParamInfo,
getter_AddRefs(iinfo));
if (NS_FAILED(rv)) {
return rv;
}
}
return ArrayXPTCMiniVariantToVariant(arrayType.TagPart(), aMiniVariant,
aArrayLength, iinfo, aVariant);
}
// else
if (type.IsInterfacePointer()) {
rv = aInterfaceInfo->GetInfoForParam(aMethodIndex, aParamInfo,
getter_AddRefs(iinfo));
if (NS_FAILED(rv)) {
return rv;
}
}
return XPTCMiniVariantToVariant(type_tag, aMiniVariant, iinfo, aVariant);
}
nsresult
WSPProxy::WrapInPropertyBag(nsISupports* aInstance,
nsIInterfaceInfo* aInterfaceInfo,
nsIPropertyBag** aPropertyBag)
{
*aPropertyBag = nsnull;
nsresult rv;
nsCOMPtr<nsIWebServiceComplexTypeWrapper> wrapper =
do_CreateInstance(NS_WEBSERVICECOMPLEXTYPEWRAPPER_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
return rv;
}
rv = wrapper->Init(aInstance, aInterfaceInfo);
if (NS_FAILED(rv)) {
return rv;
}
return CallQueryInterface(wrapper, aPropertyBag);
}
nsresult
WSPProxy::XPTCMiniVariantToVariant(uint8 aTypeTag, nsXPTCMiniVariant aResult,
nsIInterfaceInfo* aInterfaceInfo,
nsIVariant** aVariant)
{
nsresult rv;
// If a variant is passed in, just return it as is.
if (aTypeTag == nsXPTType::T_INTERFACE) {
nsISupports* inst = (nsISupports*)aResult.val.p;
nsCOMPtr<nsIVariant> instVar = do_QueryInterface(inst);
if (instVar) {
*aVariant = instVar;
NS_ADDREF(*aVariant);
return NS_OK;
}
}
nsCOMPtr<nsIWritableVariant> var =
do_CreateInstance(NS_VARIANT_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
return rv;
}
switch (aTypeTag) {
case nsXPTType::T_I8:
var->SetAsInt8(aResult.val.i8);
break;
case nsXPTType::T_I16:
var->SetAsInt16(aResult.val.i16);
break;
case nsXPTType::T_I32:
var->SetAsInt32(aResult.val.i32);
break;
case nsXPTType::T_I64:
var->SetAsInt64(aResult.val.i64);
break;
case nsXPTType::T_U8:
var->SetAsUint8(aResult.val.u8);
break;
case nsXPTType::T_U16:
var->SetAsUint16(aResult.val.u16);
break;
case nsXPTType::T_U32:
var->SetAsUint32(aResult.val.u32);
break;
case nsXPTType::T_U64:
var->SetAsUint64(aResult.val.u64);
break;
case nsXPTType::T_FLOAT:
var->SetAsFloat(aResult.val.f);
break;
case nsXPTType::T_DOUBLE:
var->SetAsDouble(aResult.val.d);
break;
case nsXPTType::T_BOOL:
var->SetAsBool(aResult.val.b);
break;
case nsXPTType::T_CHAR:
var->SetAsChar(aResult.val.c);
break;
case nsXPTType::T_WCHAR:
var->SetAsWChar(aResult.val.wc);
break;
case nsXPTType::T_CHAR_STR:
var->SetAsString(NS_STATIC_CAST(char*, aResult.val.p));
break;
case nsXPTType::T_WCHAR_STR:
var->SetAsWString(NS_STATIC_CAST(PRUnichar*, aResult.val.p));
break;
case nsXPTType::T_DOMSTRING:
case nsXPTType::T_ASTRING:
var->SetAsAString(*((nsAString*)aResult.val.p));
break;
case nsXPTType::T_INTERFACE:
{
nsISupports* instance = (nsISupports*)aResult.val.p;
if (instance) {
nsCOMPtr<nsIPropertyBag> propBag;
rv = WrapInPropertyBag(instance, aInterfaceInfo,
getter_AddRefs(propBag));
if (NS_FAILED(rv)) {
return rv;
}
var->SetAsInterface(NS_GET_IID(nsIPropertyBag), propBag);
// AFAICT, there is no need to release the instance here
// because the caller who owns the object should be releasing it.
// NS_RELEASE(instance);
}
else {
var->SetAsEmpty();
}
break;
}
default:
NS_ERROR("Bad attribute type for complex type interface");
rv = NS_ERROR_FAILURE;
}
*aVariant = var;
NS_ADDREF(*aVariant);
return rv;
}
nsresult
WSPProxy::ArrayXPTCMiniVariantToVariant(uint8 aTypeTag,
nsXPTCMiniVariant aResult,
PRUint32 aLength,
nsIInterfaceInfo* aInterfaceInfo,
nsIVariant** aVariant)
{
nsresult rv;
nsCOMPtr<nsIWritableVariant> retvar =
do_CreateInstance(NS_VARIANT_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
return rv;
}
if (aLength) {
PRUint32 i = 0;
void* array = aResult.val.p;
void* entries;
nsISupports** entriesSup = nsnull;
const nsIID* iid = nsnull;
switch (aTypeTag) {
case nsXPTType::T_I8:
case nsXPTType::T_I16:
case nsXPTType::T_I32:
case nsXPTType::T_I64:
case nsXPTType::T_U8:
case nsXPTType::T_U16:
case nsXPTType::T_U32:
case nsXPTType::T_U64:
case nsXPTType::T_FLOAT:
case nsXPTType::T_DOUBLE:
case nsXPTType::T_BOOL:
case nsXPTType::T_CHAR:
case nsXPTType::T_WCHAR:
case nsXPTType::T_CHAR_STR:
case nsXPTType::T_WCHAR_STR:
entries = array;
break;
case nsXPTType::T_INTERFACE:
{
aInterfaceInfo->GetIIDShared(&iid);
if (iid->Equals(NS_GET_IID(nsIVariant))) {
entries = array;
}
else {
entriesSup = (nsISupports**)nsMemory::Alloc(aLength *
sizeof(nsISupports*));
if (!entriesSup) {
return NS_ERROR_OUT_OF_MEMORY;
}
const nsIID& propbagIID = NS_GET_IID(nsIPropertyBag);
iid = &propbagIID;
entries = (void*)entriesSup;
for(i = 0; i < aLength; i++) {
nsISupports* instance = *((nsISupports**)array + i);
nsISupports** outptr = entriesSup + i;
if (instance) {
nsCOMPtr<nsIPropertyBag> propBag;
rv = WrapInPropertyBag(instance, aInterfaceInfo,
getter_AddRefs(propBag));
if (NS_FAILED(rv)) {
break;
}
propBag->QueryInterface(NS_GET_IID(nsISupports),
(void**)outptr);
}
else {
*outptr = nsnull;
}
}
}
aTypeTag = nsXPTType::T_INTERFACE_IS;
break;
}
default:
NS_ERROR("Conversion of illegal array type");
return NS_ERROR_FAILURE;
}
if (NS_SUCCEEDED(rv)) {
rv = retvar->SetAsArray(aTypeTag, iid, aLength, entries);
}
if (entriesSup) {
NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(i, entriesSup);
}
}
else {
retvar->SetAsEmpty();
}
if (NS_SUCCEEDED(rv)) {
*aVariant = retvar;
NS_ADDREF(*aVariant);
}
return rv;
}
nsresult
WSPProxy::VariantToInParameter(nsIInterfaceInfo* aInterfaceInfo,
PRUint32 aMethodIndex,
const nsXPTParamInfo* aParamInfo,
nsIVariant* aVariant,
nsXPTCVariant* aXPTCVariant)
{
nsXPTType type;
nsresult rv = aInterfaceInfo->GetTypeForParam(aMethodIndex, aParamInfo,
0, &type);
if (NS_FAILED(rv)) {
return rv;
}
uint8 type_tag = type.TagPart();
nsCOMPtr<nsIInterfaceInfo> iinfo;
if (type.IsArray()) {
nsXPTType arrayType;
rv = aInterfaceInfo->GetTypeForParam(aMethodIndex, aParamInfo,
1, &arrayType);
if (NS_FAILED(rv)) {
return rv;
}
if (arrayType.IsInterfacePointer()) {
rv = aInterfaceInfo->GetInfoForParam(aMethodIndex, aParamInfo,
getter_AddRefs(iinfo));
if (NS_FAILED(rv)) {
return rv;
}
}
aXPTCVariant[0].type = nsXPTType::T_U32;
aXPTCVariant[1].type = nsXPTType::T_ARRAY;
aXPTCVariant[1].SetValIsArray();
return VariantToArrayValue(arrayType.TagPart(), aXPTCVariant, aXPTCVariant+1,
iinfo, aVariant);
}
// Set the param's type on the XPTCVariant because xptcinvoke's
// invoke_copy_to_stack depends on it. This fixes bug 203434.
aXPTCVariant->type = type;
// else
if (type.IsInterfacePointer()) {
rv = aInterfaceInfo->GetInfoForParam(aMethodIndex, aParamInfo,
getter_AddRefs(iinfo));
if (NS_FAILED(rv)) {
return rv;
}
}
if (type_tag == nsXPTType::T_DOMSTRING) {
// T_DOMSTRING values are expected to be stored in an nsAString
// object pointed to by the nsXPTCVariant...
return VariantToValue(type_tag, aXPTCVariant->val.p, iinfo, aVariant);
}
// else
// ... but other types are expected to be stored directly in the
// variant itself.
return VariantToValue(type_tag, &aXPTCVariant->val, iinfo, aVariant);
}
nsresult
WSPProxy::VariantToOutParameter(nsIInterfaceInfo* aInterfaceInfo,
PRUint32 aMethodIndex,
const nsXPTParamInfo* aParamInfo,
nsIVariant* aVariant,
nsXPTCMiniVariant* aMiniVariant)
{
nsXPTType type;
nsresult rv = aInterfaceInfo->GetTypeForParam(aMethodIndex, aParamInfo,
0, &type);
if (NS_FAILED(rv)) {
return rv;
}
uint8 type_tag = type.TagPart();
nsCOMPtr<nsIInterfaceInfo> iinfo;
if (type.IsArray()) {
nsXPTType arrayType;
rv = aInterfaceInfo->GetTypeForParam(aMethodIndex, aParamInfo,
1, &arrayType);
if (NS_FAILED(rv)) {
return rv;
}
if (arrayType.IsInterfacePointer()) {
rv = aInterfaceInfo->GetInfoForParam(aMethodIndex, aParamInfo,
getter_AddRefs(iinfo));
if (NS_FAILED(rv)) {
return rv;
}
}
return VariantToArrayValue(arrayType.TagPart(),
aMiniVariant, aMiniVariant + 1,
iinfo, aVariant);
}
// else
if (type.IsInterfacePointer()) {
rv = aInterfaceInfo->GetInfoForParam(aMethodIndex, aParamInfo,
getter_AddRefs(iinfo));
if (NS_FAILED(rv)) {
return rv;
}
}
return VariantToValue(type_tag, aMiniVariant->val.p, iinfo, aVariant);
}
nsresult
WSPProxy::WrapInComplexType(nsIPropertyBag* aPropertyBag,
nsIInterfaceInfo* aInterfaceInfo,
nsISupports** aComplexType)
{
*aComplexType = nsnull;
nsRefPtr<WSPPropertyBagWrapper> wrapper = new WSPPropertyBagWrapper();
if (!wrapper) {
return NS_ERROR_OUT_OF_MEMORY;
}
nsresult rv = wrapper->Init(aPropertyBag, aInterfaceInfo);
if (NS_FAILED(rv)) {
return rv;
}
wrapper->QueryInterface(NS_GET_IID(nsISupports), (void**)aComplexType);
return NS_OK;
}
nsresult
WSPProxy::VariantToValue(uint8 aTypeTag, void* aValue,
nsIInterfaceInfo* aInterfaceInfo,
nsIVariant* aProperty)
{
nsresult rv = NS_OK;
switch(aTypeTag) {
case nsXPTType::T_I8:
rv = aProperty->GetAsInt8((PRUint8*)aValue);
break;
case nsXPTType::T_I16:
rv = aProperty->GetAsInt16((PRInt16*)aValue);
break;
case nsXPTType::T_I32:
rv = aProperty->GetAsInt32((PRInt32*)aValue);
break;
case nsXPTType::T_I64:
rv = aProperty->GetAsInt64((PRInt64*)aValue);
break;
case nsXPTType::T_U8:
rv = aProperty->GetAsUint8((PRUint8*)aValue);
break;
case nsXPTType::T_U16:
rv = aProperty->GetAsUint16((PRUint16*)aValue);
break;
case nsXPTType::T_U32:
rv = aProperty->GetAsUint32((PRUint32*)aValue);
break;
case nsXPTType::T_U64:
rv = aProperty->GetAsUint64((PRUint64*)aValue);
break;
case nsXPTType::T_FLOAT:
rv = aProperty->GetAsFloat((float*)aValue);
break;
case nsXPTType::T_DOUBLE:
rv = aProperty->GetAsDouble((double*)aValue);
break;
case nsXPTType::T_BOOL:
rv = aProperty->GetAsBool((PRBool*)aValue);
break;
case nsXPTType::T_CHAR:
rv = aProperty->GetAsChar((char*)aValue);
break;
case nsXPTType::T_WCHAR:
rv = aProperty->GetAsWChar((PRUnichar*)aValue);
break;
case nsXPTType::T_CHAR_STR:
rv = aProperty->GetAsString((char**)aValue);
break;
case nsXPTType::T_WCHAR_STR:
rv = aProperty->GetAsWString((PRUnichar**)aValue);
break;
case nsXPTType::T_DOMSTRING:
case nsXPTType::T_ASTRING:
rv = aProperty->GetAsAString(*(nsAString*)aValue);
break;
case nsXPTType::T_INTERFACE:
{
const nsIID* iid;
aInterfaceInfo->GetIIDShared(&iid);
PRUint16 dataType;
aProperty->GetDataType(&dataType);
if (dataType == nsIDataType::VTYPE_EMPTY) {
*(nsISupports**)aValue = nsnull;
}
else if (iid->Equals(NS_GET_IID(nsIVariant))) {
*(nsIVariant**)aValue = aProperty;
NS_ADDREF(*(nsIVariant**)aValue);
}
else {
nsCOMPtr<nsISupports> sup;
rv = aProperty->GetAsISupports(getter_AddRefs(sup));
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsIPropertyBag> propBag = do_QueryInterface(sup, &rv);
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsISupports> wrapper;
rv = WrapInComplexType(propBag, aInterfaceInfo,
getter_AddRefs(wrapper));
if (NS_FAILED(rv)) {
return rv;
}
rv = wrapper->QueryInterface(*iid, (void**)aValue);
}
break;
}
default:
NS_ERROR("Bad attribute type for complex type interface");
rv = NS_ERROR_FAILURE;
}
return rv;
}
nsresult
WSPProxy::VariantToArrayValue(uint8 aTypeTag,
nsXPTCMiniVariant* aResultSize,
nsXPTCMiniVariant* aResultArray,
nsIInterfaceInfo* aInterfaceInfo,
nsIVariant* aProperty)
{
void* array;
PRUint16 type;
PRUint32 count;
nsIID arrayIID;
nsresult rv = aProperty->GetAsArray(&type, &arrayIID, &count, &array);
if (NS_FAILED(rv)) {
return rv;
}
aResultSize->val.u32 = count;
switch (aTypeTag) {
case nsXPTType::T_I8:
case nsXPTType::T_U8:
case nsXPTType::T_I16:
case nsXPTType::T_U16:
case nsXPTType::T_I32:
case nsXPTType::T_U32:
case nsXPTType::T_I64:
case nsXPTType::T_U64:
case nsXPTType::T_FLOAT:
case nsXPTType::T_DOUBLE:
case nsXPTType::T_BOOL:
case nsXPTType::T_CHAR:
case nsXPTType::T_WCHAR:
case nsXPTType::T_CHAR_STR:
case nsXPTType::T_WCHAR_STR:
aResultArray->val.p = array;
break;
case nsXPTType::T_INTERFACE:
case nsXPTType::T_INTERFACE_IS:
{
if (arrayIID.Equals(NS_GET_IID(nsIVariant))) {
aResultArray->val.p = array;
}
else if (!arrayIID.Equals(NS_GET_IID(nsIPropertyBag))) {
NS_ERROR("Array of complex types should be represented by property "
"bags");
return NS_ERROR_FAILURE;
}
else {
nsISupports** outptr =
(nsISupports**)nsMemory::Alloc(count * sizeof(nsISupports*));
if (!outptr) {
return NS_ERROR_OUT_OF_MEMORY;
}
nsISupports** arraySup = (nsISupports**)array;
const nsIID* iid;
aInterfaceInfo->GetIIDShared(&iid);
PRUint32 i;
for (i = 0; i < count; i++) {
nsCOMPtr<nsIPropertyBag> propBag(do_QueryInterface(arraySup[i]));
if (!propBag) {
*(outptr + i) = nsnull;
}
else {
nsCOMPtr<nsISupports> wrapper;
rv = WrapInComplexType(propBag, aInterfaceInfo,
getter_AddRefs(wrapper));
if (NS_FAILED(rv)) {
NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(i, outptr);
return rv;
}
rv = wrapper->QueryInterface(*iid, (void**)(outptr + i));
if (NS_FAILED(rv)) {
NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(i, outptr);
return rv;
}
}
}
aResultArray->val.p = outptr;
}
break;
}
default:
NS_ERROR("Conversion of illegal array type");
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
WSPProxy::GetInterfaceInfo(nsIInterfaceInfo** info)
{
NS_ENSURE_ARG_POINTER(info);
*info = mPrimaryInterface;
NS_ADDREF(*info);
return NS_OK;
}
///////////////////////////////////////////////////
//
// Implementation of nsIWebServiceProxy
//
///////////////////////////////////////////////////
/* readonly attribute nsIWSDLPort port; */
NS_IMETHODIMP
WSPProxy::GetPort(nsIWSDLPort * *aPort)
{
NS_ENSURE_ARG_POINTER(aPort);
*aPort = mPort;
NS_IF_ADDREF(*aPort);
return NS_OK;
}
/* readonly attribute boolean isAsync; */
NS_IMETHODIMP
WSPProxy::GetIsAsync(PRBool *aIsAsync)
{
NS_ENSURE_ARG_POINTER(aIsAsync);
*aIsAsync = mIsAsync;
return NS_OK;
}
/* readonly attribute AString qualifier; */
NS_IMETHODIMP
WSPProxy::GetQualifier(nsAString & aQualifier)
{
aQualifier.Assign(mQualifier);
return NS_OK;
}
/* readonly attribute nsISimpleEnumerator pendingCalls; */
NS_IMETHODIMP
WSPProxy::GetPendingCalls(nsISimpleEnumerator * *aPendingCalls)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
WSPProxy::GetInterfaceName(PRBool listener, char** retval)
{
if (!mPrimaryInterface) {
return NS_ERROR_FAILURE;
}
const char* rawName;
nsresult rv = mPrimaryInterface->GetNameShared(&rawName);
if (NS_FAILED(rv)) {
return rv;
}
nsCAutoString name;
if (listener) {
if (mIsAsync) {
name.Assign(rawName, strlen(rawName) - (sizeof("Async")-1) );
}
else {
name.Assign(rawName);
}
name.Append("Listener");
}
else {
name.Assign(rawName);
}
*retval = (char*) nsMemory::Clone(name.get(), name.Length()+1);
return *retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
/* readonly attribute string primaryInterfaceName; */
NS_IMETHODIMP
WSPProxy::GetPrimaryInterfaceName(char * *aPrimaryInterfaceName)
{
return GetInterfaceName(PR_FALSE, aPrimaryInterfaceName);
}
/* readonly attribute string primaryAsyncListenerInterfaceName; */
NS_IMETHODIMP
WSPProxy::GetPrimaryAsyncListenerInterfaceName(char * *aPrimaryAsyncListenerInterfaceName)
{
return GetInterfaceName(PR_TRUE, aPrimaryAsyncListenerInterfaceName);
}
/* readonly attribute nsIScriptableInterfaces interfaces; */
NS_IMETHODIMP
WSPProxy::GetInterfaces(nsIScriptableInterfaces * *aInterfaces)
{
*aInterfaces = mInterfaces;
NS_IF_ADDREF(*aInterfaces);
return NS_OK;
}
///////////////////////////////////////////////////
//
// Implementation of nsIClassInfo
//
///////////////////////////////////////////////////
/* void getInterfaces (out PRUint32 count, [array, size_is (count),
retval] out nsIIDPtr array); */
NS_IMETHODIMP
WSPProxy::GetInterfaces(PRUint32 *count, nsIID * **array)
{
if (!mIID) {
return NS_ERROR_NOT_INITIALIZED;
}
*count = 2;
nsIID** iids = NS_STATIC_CAST(nsIID**, nsMemory::Alloc(2 * sizeof(nsIID*)));
if (!iids) {
return NS_ERROR_OUT_OF_MEMORY;
}
iids[0] = NS_STATIC_CAST(nsIID *, nsMemory::Clone(mIID, sizeof(nsIID)));
if (NS_UNLIKELY(!iids[0])) {
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(0, iids);
return NS_ERROR_OUT_OF_MEMORY;
}
const nsIID& wsiid = NS_GET_IID(nsIWebServiceProxy);
iids[1] = NS_STATIC_CAST(nsIID *, nsMemory::Clone(&wsiid, sizeof(nsIID)));
if (NS_UNLIKELY(!iids[1])) {
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(1, iids);
return NS_ERROR_OUT_OF_MEMORY;
}
*array = iids;
return NS_OK;
}
/* nsISupports getHelperForLanguage (in PRUint32 language); */
NS_IMETHODIMP
WSPProxy::GetHelperForLanguage(PRUint32 language, nsISupports **_retval)
{
*_retval = nsnull;
return NS_OK;
}
/* readonly attribute string contractID; */
NS_IMETHODIMP
WSPProxy::GetContractID(char * *aContractID)
{
*aContractID = nsnull;
return NS_OK;
}
/* readonly attribute string classDescription; */
NS_IMETHODIMP
WSPProxy::GetClassDescription(char * *aClassDescription)
{
*aClassDescription = nsnull;
return NS_OK;
}
/* readonly attribute nsCIDPtr classID; */
NS_IMETHODIMP
WSPProxy::GetClassID(nsCID * *aClassID)
{
*aClassID = nsnull;
return NS_OK;
}
/* readonly attribute PRUint32 implementationLanguage; */
NS_IMETHODIMP
WSPProxy::GetImplementationLanguage(PRUint32 *aImplementationLanguage)
{
*aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
return NS_OK;
}
/* readonly attribute PRUint32 flags; */
NS_IMETHODIMP
WSPProxy::GetFlags(PRUint32 *aFlags)
{
*aFlags = nsIClassInfo::DOM_OBJECT;
return NS_OK;
}
/* [notxpcom] readonly attribute nsCID classIDNoAlloc; */
NS_IMETHODIMP
WSPProxy::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
{
return NS_ERROR_NOT_AVAILABLE;
}
void
WSPProxy::GetListenerInterfaceInfo(nsIInterfaceInfo** aInfo)
{
*aInfo = mListenerInterfaceInfo;
NS_IF_ADDREF(*aInfo);
}
void
WSPProxy::CallCompleted(WSPCallContext* aContext)
{
mPendingCalls.RemoveObject(aContext);
}