Web Services in Objective C Part 2

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, &paramDesc); if (err != noErr) fprintf(stderr, "\tCan't get parameter %4.4s - %d returned\n", &parameter, err); else { int len = AEGetDescDataSize(&paramDesc); char* buffer = new char[len]; AEGetDescData(&paramDesc, 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(&paramDesc); 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, &paramRecord); if (err == noErr) err = AEPutParamDesc(&paramRecord, keyASUserRecordFields, soapParms); // Put the parameter record into the direct object err = AEPutParamDesc(&directObject, keyRPCMethodParam, &paramRecord); cleanupErr(err); AEDisposeDesc(&paramRecord); // 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;
}