This is the SoapUtils.h – you include this.
Again if someone knows how to make this a set of utilities in a separate file that are linked together – let me know. I am an Xcode Newbie :)
/*
* SoapUtils.h
* SakaiDesktop
*
* Created by Charles Severance on 12/29/05.
* Copyright 2005 __MyCompanyName__. All rights reserved.
*
*/
#include
#define cleanupErr(err) \
while (err != noErr) { fprintf(stderr, “Failed at line %d, error %d\n”, __LINE__, err); goto cleanup; }
static OSStatus getUserRecordField(const AEDesc* record, const char* fieldName, OSType desiredType, void* buffer, Size bufferSize, Size* actualSize)
{
// Extract the userfield list from the record.
AEDesc userField;
OSStatus err = AEGetParamDesc(record, keyASUserRecordFields, typeAEList, &userField);
cleanupErr(err);
// The userfield is an array of name,data, so we compare the name against what we’re looking for,
// and if it maches return nameIndex + 1 coerced appropriately
long count;
err = AECountItems(&userField, &count);
cleanupErr(err);
for (long i = 1; i <= count; i += 2) {
char tmpName[255];
Size tmpNameSize;
OSType tossKeyword;
OSType tossType;
err = AEGetNthPtr(&userField, i, typeChar, &tossKeyword, &tossType, tmpName, sizeof(tmpName), &tmpNameSize);
cleanupErr(err);
if (strncmp(fieldName, tmpName, tmpNameSize) == 0) {
err = AEGetNthPtr(&userField, i + 1, desiredType, &tossKeyword, &tossType, buffer, bufferSize, actualSize);
cleanupErr(err);
break;
}
}
cleanup:
return err;
}
static void dumpDebug(const char* msg, const AppleEvent* event, OSType parameter)
{
fprintf(stderr, "%s:\n", msg);
AEDesc paramDesc;
OSErr err = AEGetParamDesc(event, parameter, typeChar, ¶mDesc);
if (err != noErr)
fprintf(stderr, "\tCan't get parameter %4.4s - %d returned\n", ¶meter, err);
else {
int len = AEGetDescDataSize(¶mDesc);
char* buffer = new char[len];
AEGetDescData(¶mDesc, buffer, len);
char* p = buffer;
char* pEnd = buffer + len;
while (p < pEnd) {
char* pNext = strpbrk(p, "\r\n");
if (pNext == NULL)
pNext = pEnd;
else {
while (pNext < pEnd && (*pNext == '\r' || *pNext == '\n')) {
*pNext++ = '\0';
}
}
fprintf(stderr, "\t%.*s\n", pNext - p, p);
p = pNext;
}
AEDisposeDesc(¶mDesc);
delete[] buffer;
}
fprintf(stderr, "\n\n");
}
/* Sample code
// Java Signature in jws
// public String mymethod(String id, Integer i, Double d)
OSErr err;
AEDesc soapParms;
err = createSoapParameters(&soapParms);
err = addSoapParameter(&soapParms, "id", typeChar, "fred");
int i=25;
err = addSoapParameter(&soapParms, "i", typeSInt32, &i);
double d=123.456;
err = addSoapParameter(&soapParms, "d", typeIEEE64BitFloatingPoint, &d);
char buffer[100000];
char errorMessage[1024];
err = makeSoapCall(url, "mymethod", &soapParms ,buffer, sizeof(buffer), errorMessage, sizeof(errorMessage), false, true);
AEDisposeDesc(&soapParms);
if ( err == noErr ) {
fprintf(stderr,"Success String = %s!\n\n", buffer);
} else {
fprintf(stderr,"Error String = %s!\n\n", errorMessage);
}
*/
static OSStatus createSoapParameters(AEDesc* termsList)
{
OSErr err = AECreateList(NULL, 0, false, termsList);
return err;
}
static OSStatus addSoapParameter(AEDesc* termsList, const char* name, OSType dataType, const void* data)
{
OSErr err = AEPutPtr(termsList, 0, typeChar, name, strlen(name));
if ( err != noErr ) return err;
switch (dataType) {
case typeChar:
err = AEPutPtr(termsList, 0, typeChar, data, strlen((const char*)data));
break;
case typeSInt32:
err = AEPutPtr(termsList, 0, typeSInt32, data, 4);
break;
case typeIEEE64BitFloatingPoint:
err = AEPutPtr(termsList, 0, typeIEEE64BitFloatingPoint, data, 8);
break;
default:
fprintf(stderr,"Error, unknown type in addSoapParameter: %4s\n\n",dataType);
}
return err;
}
static OSErr makeSoapCall(const char* url, const char* methodName, AEDesc* soapParms,
char* buffer, int bufferSize,
char *errorMessage, int errorMessageLength,
int doDebug, int doDebugError )
{
if ( bufferSize < 1 || errorMessageLength < 1 ) return eLenErr;
errorMessage[0] = '\0'; // No Error Message
OSErr err;
AEDesc targetAddress;
// Create the target address
err = AECreateDesc(typeApplicationURL, url, strlen(url), &targetAddress);
cleanupErr(err);
AppleEvent event;
err = AECreateAppleEvent(kAERPCClass, kAESOAPScheme, &targetAddress, kAutoGenerateReturnID, kAnyTransactionID, &event);
cleanupErr(err);
AEDisposeDesc(&targetAddress);
// Create the parameters for the event - the direct object is a record that contains
// the method name, and a list of parameters
AEDesc directObject;
err = AECreateList(NULL, 0, true, &directObject);
cleanupErr(err);
// Put the method name
err = AEPutParamPtr(&directObject, keyRPCMethodName, typeChar, methodName, strlen(methodName));
cleanupErr(err);
AEDesc paramRecord;
err = AECreateList(NULL, 0, true, ¶mRecord);
if (err == noErr)
err = AEPutParamDesc(¶mRecord, keyASUserRecordFields, soapParms);
// Put the parameter record into the direct object
err = AEPutParamDesc(&directObject, keyRPCMethodParam, ¶mRecord);
cleanupErr(err);
AEDisposeDesc(¶mRecord);
// Additional pieces for soap are the method namespace, namespaceURI and
// SOAPAction. If the SOAPAction isn't explicitly specified, it
// will be the path part of the url (in this case, "/examples")
// You don't need to supply the method namespace...
// static const char* methodNameSpaceURI = "http://www.soapware.org/";
// err = AEPutParamPtr(&directObject, keySOAPMethodNameSpaceURI, typeChar, methodNameSpaceURI, strlen(methodNameSpaceURI));
// cleanupErr(err);
// Put the direct object into the event
err = AEPutParamDesc(&event, keyDirectObject, &directObject);
cleanupErr(err);
AEDisposeDesc(&directObject);
// Request debugging information
if ( doDebug ) {
SInt32 debugAttr = kAEDebugXMLDebugAll;
err = AEPutAttributePtr(&event, keyXMLDebuggingAttr, typeSInt32, &debugAttr, sizeof(debugAttr));
}
// Finally, send the event (we're using AESendMessage so we don't link against Carbon, just ApplicationServices)
AppleEvent reply;
AEInitializeDescInline(&reply);
err = AESendMessage(&event, &reply, kAEWaitReply, kAEDefaultTimeout);
cleanupErr(err);
// The direct object contains our result (the name of the state)
Size actualSize;
// See if we got a return value
err = AEGetParamPtr(&reply, keyDirectObject, typeChar, NULL, buffer, bufferSize, &actualSize);
// Upon success return after optionally dumping information
if ( err == noErr ) {
if ( actualSize < bufferSize ) {
buffer[actualSize] = '\0'; // Terminate
} else {
buffer [ bufferSize-1 ] = '\0';
err = eLenErr;
if ( errorMessageLength > 60 ) sprintf(errorMessage,”SOAP return buffer too short partial results returned, length= %d”, bufferSize);
}
}
// If we still have no error, lets return
if ( err == noErr ) {
if ( doDebug ) {
dumpDebug(“HTTP POST header”, &reply, keyAEPOSTHeaderData);
dumpDebug(“XML Request”, &reply, keyAEXMLRequestData);
dumpDebug(“HTTP Reply header”, &reply, keyAEReplyHeaderData);
dumpDebug(“XML Reply”, &reply, keyAEXMLReplyData);
}
return err;
}
// Dump debug information in this error case
if ( doDebug || doDebugError ) {
dumpDebug(“HTTP POST header”, &reply, keyAEPOSTHeaderData);
dumpDebug(“XML Request”, &reply, keyAEXMLRequestData);
dumpDebug(“HTTP Reply header”, &reply, keyAEReplyHeaderData);
dumpDebug(“XML Reply”, &reply, keyAEXMLReplyData);
}
// Something is wrong, lets whip up a nice return error string for them
err = AEGetParamPtr(&reply, keyErrorString, typeChar, NULL, errorMessage, errorMessageLength, &actualSize);
// If the host is up, the web service is right, and the method name is right,
// and a parameter name is wrong (i.e. bad signature) – we come here with
// A 1701 (errAEDescNotFound – Descriptor Record Not Found)
// There may be other scenarrios that get us here – but for now, lets return the best
// error message we know about – it is better than a generic “interal fault 1701″
if ( err != noErr ) {
if ( errorMessageLength > 60 ) sprintf(errorMessage,”No Matching Web Service: %i\n\n”,err);
} else { // Normal error situation, like AxisFault, Error message already set
// Host does not exist: Transport error!
// Host is up, but no web service: java.io.FileNotFoundException: /SakaiLogin.jws!
// Host is up, no matching method: No such operation ‘login’!
// force error return
err = errAEDescNotFound;
}
cleanup:
if ( doDebug || doDebugError ) {
fprintf(stderr,”makeSoapCall() error=%d url=%s (%s) message=%s\n”,err,url,methodName, errorMessage);
}
return err;
}