예제 #1
0
OperationContext ClientCIMOMHandleRep::getResponseContext()
{
    OperationContext ctx;

    Thread* curThrd = Thread::getCurrent();
    if (curThrd == NULL)
    {
        ctx.insert(ContentLanguageListContainer(ContentLanguageList()));
    }
    else
    {
        ContentLanguageList* contentLangs = (ContentLanguageList*)
            curThrd->reference_tsd(TSD_CIMOM_HANDLE_CONTENT_LANGUAGES);
        curThrd->dereference_tsd();

        if (contentLangs == NULL)
        {
            ctx.insert(ContentLanguageListContainer(ContentLanguageList()));
        }
        else
        {
            ctx.insert(ContentLanguageListContainer(*contentLangs));
            // delete the old tsd to free the memory
            curThrd->delete_tsd(TSD_CIMOM_HANDLE_CONTENT_LANGUAGES);
        }
    }

    return ctx;
}
예제 #2
0
void CIMExportClient::exportIndication(
   const String& url,
   const CIMInstance& instanceName,
   const ContentLanguageList& contentLanguages)
{
    PEG_METHOD_ENTER (TRC_EXPORT_CLIENT, "CIMExportClient::exportIndication()");

    try
    {
        // encode request
        CIMRequestMessage* request = new CIMExportIndicationRequestMessage(
            String::EMPTY,
            url,
            instanceName,
            QueueIdStack(),
            String::EMPTY,
            String::EMPTY);

        request->operationContext.set
            (ContentLanguageListContainer(contentLanguages));

        PEG_TRACE ((TRC_INDICATION_GENERATION, Tracer::LEVEL4,
            "Exporting %s Indication for destination %s:%d%s",
            (const char*)(instanceName.getClassName().getString().
            getCString()),
            (const char*)(_connectHost.getCString()), _connectPortNumber,
            (const char*)(url.getCString())));

        Message* message = _doRequest(request,
            CIM_EXPORT_INDICATION_RESPONSE_MESSAGE);

        PEG_TRACE ((TRC_INDICATION_GENERATION, Tracer::LEVEL4,
            "%s Indication for destination %s:%d%s exported successfully",
            (const char*)(instanceName.getClassName().getString().
            getCString()),
            (const char*)(_connectHost.getCString()), _connectPortNumber,
            (const char*)(url.getCString())));

        CIMExportIndicationResponseMessage* response =
            (CIMExportIndicationResponseMessage*)message;

        AutoPtr<CIMExportIndicationResponseMessage> ap(response);
    }
    catch (const Exception& e)
    {
        PEG_TRACE((TRC_DISCARDED_DATA, Tracer::LEVEL1,
            "Failed to export indication: %s",
            (const char*)e.getMessage().getCString()));
        throw;
    }
    catch (...)
    {
        PEG_TRACE_CSTRING (TRC_DISCARDED_DATA, Tracer::LEVEL1,
            "Failed to export indication");
        throw;
    }
    PEG_METHOD_EXIT();
}
ThreadReturnType PEGASUS_THREAD_CDECL
CIMListenerIndicationDispatcherRep::deliver_routine(void *param)
{
    CIMListenerIndicationDispatchEvent* event =
        static_cast<CIMListenerIndicationDispatchEvent*>(param);

    if(event!=NULL)
    {
        CIMIndicationConsumer* consumer = event->getConsumer();
        OperationContext context;
            context.insert(ContentLanguageListContainer(
                        event->getContentLanguages()));
        if(consumer)
        {
            consumer->consumeIndication(context,
                event->getURL(),event->getIndicationInstance());
        }

        delete event;
    }

    return (0);
}
// This is only called from SimpleResponseHandler.deliver() but lives in this
// class because all asyncronous response must have a "response" pointer
// to go through. Only operation classes have a response pointer
void OperationResponseHandler::send(Boolean isComplete)
{
    // It is possible to instantiate this class directly (not a derived
    // class, which would also inherit from SimpleResponseHandler).
    // The caller would do this only if the operation does not have any
    // data to be returned.

    SimpleResponseHandler* simpleP =
        dynamic_cast<SimpleResponseHandler*>(this);
    if (simpleP == 0)
    {
        // if there is no data to be returned, then the message should NEVER be
        // incomplete (even on an error)
        PEGASUS_ASSERT(isComplete);
        return;
    }

    // some handlers do not send async because their callers cannot handle
    // partial responses. If this is the case, stop here.

    if (!isAsync())
    {
        // preserve traditional behavior
        if (isComplete)
        {
            if (_response != 0)
            {
                _response->operationContext.set(
                    ContentLanguageListContainer(simpleP->getLanguages()));
            }
            transfer();
        }

        return;
    }

    SimpleResponseHandler& simple = *simpleP;
    PEGASUS_ASSERT(_response);
    Uint32 objectCount = simple.size();

    // have not reached threshold yet
    if ((isComplete == false) && (objectCount < _responseObjectThreshold))
    {
        return;
    }

    CIMResponseMessage* response = _response;

    // for complete responses, just use the one handed down from caller
    // otherwise, create our own that the caller never sees but is
    // utilized for async responses underneath

    if (isComplete == false)
    {
        _response = _request->buildResponse();
    }

    _response->setComplete(isComplete);
    _responseObjectTotal += objectCount;

    // since we are reusing response for every chunk, keep track of original
    // count
    _response->setIndex(_responseMessageTotal++);

    // set the originally allocated response to one more than the current.
    // The reason for doing this is proactive in case of an exception. This
    // allows the last response to be set as it may not re-enter this code.

    if (isComplete == false)
    {
        response->setIndex(_responseMessageTotal);
    }

    validate();

    if (_response->cimException.getCode() != CIM_ERR_SUCCESS)
    {
        simple.clear();
    }

    PEG_TRACE((
        TRC_PROVIDERMANAGER,
        Tracer::LEVEL4,
        "%s::transfer",
        (const char*) getClass().getCString()));

    transfer();
    simple.clear();

    _response->operationContext.set(
        ContentLanguageListContainer(simple.getLanguages()));

    // call thru ProviderManager to get externally declared entry point

    if (isComplete == false)
    {
        _responseChunkCallback(_request, _response);
    }

    // put caller's allocated response back in place. Note that _response
    // is INVALID after sending because it has been deleted externally

    _response = response;
}
void EnableIndicationsResponseHandler::deliver(
    const OperationContext& context,
    const CIMIndication& cimIndication)
{
    if (cimIndication.isUninitialized())
    {
        MessageLoaderParms message(
            "Common.Exception.UNINITIALIZED_OBJECT_EXCEPTION",
            "The object is not initialized.");

        throw CIMException(CIM_ERR_FAILED, message);
    }

    // ATTN: temporarily convert indication to instance
    CIMInstance cimInstance(cimIndication);

    //  Get list of subscription instance names from context
    Array<CIMObjectPath> subscriptionInstanceNames;

    if (context.contains(SubscriptionInstanceNamesContainer::NAME))
    {
        SubscriptionInstanceNamesContainer container =
            context.get(SubscriptionInstanceNamesContainer::NAME);

        subscriptionInstanceNames = container.getInstanceNames();
    }
    else
    {
        subscriptionInstanceNames.clear();
    }

    ContentLanguageList contentLangs;

    if (context.contains(ContentLanguageListContainer::NAME))
    {
        // Get the Content-Language for this indication.  The provider
        // does not have to add specify a language for the indication.
        ContentLanguageListContainer langContainer =
            context.get(ContentLanguageListContainer::NAME);

        contentLangs = langContainer.getLanguages();
    }
    else
    {
        // The provider did not explicitly set a Content-Language for
        // the indication.  Fall back to the lang set in this object.
        contentLangs = getLanguages();
    }

    Uint32 timeoutMilliSec = 0;
    if (context.contains(TimeoutContainer::NAME))
    {
        TimeoutContainer timeoutContainer =
            context.get(TimeoutContainer::NAME);
        timeoutMilliSec = timeoutContainer.getTimeOut();
    }

    // create message
    CIMProcessIndicationRequestMessage* request =
        new CIMProcessIndicationRequestMessage(
        XmlWriter::getNextMessageId(),
        cimInstance.getPath().getNameSpace(),
        cimInstance,
        subscriptionInstanceNames,
        _provider,
        QueueIdStack(),  // Must be filled in by the callback function
        timeoutMilliSec);

    request->operationContext = context;

    if (request->operationContext.contains(ContentLanguageListContainer::NAME))
    {
        request->operationContext.set(
            ContentLanguageListContainer(contentLangs));
    }
    else
    {
        request->operationContext.insert(
            ContentLanguageListContainer(contentLangs));
    }

    _indicationCallback(request);
}
예제 #6
0
Message* CIMClientRep::_doRequest(
    AutoPtr<CIMRequestMessage>& request,
    const Uint32 expectedResponseMessageType
)
{
    if (!_connected)
    {
        request.reset();
        throw NotConnectedException();
    }

    String messageId = XmlWriter::getNextMessageId();
    const_cast<String &>(request->messageId) = messageId;

    _authenticator.setRequestMessage(0);

    // ATTN-RK-P2-20020416: We should probably clear out the queue first.
    PEGASUS_ASSERT(getCount() == 0);  // Shouldn't be any messages in our queue

    //
    //  Set HTTP method in request to POST
    //
    //Bug 478/418 - Change this to do post call, not mpost
    request->setHttpMethod (HTTP_METHOD__POST);

// l10n
    // Set the Accept-Languages and Content-Languages into
    // the request message

    request->operationContext.set(AcceptLanguageListContainer(requestAcceptLanguages));
    request->operationContext.set(ContentLanguageListContainer(requestContentLanguages));


    //gathering statistical information about client operation
    ClientPerfDataStore* perfDataStore = ClientPerfDataStore::Instance();
    perfDataStore->reset();
    perfDataStore->setOperationType(request->getType());
    perfDataStore->setMessageID(request->messageId);


    // Sending a new request, so clear out the response Content-Languages
    responseContentLanguages = ContentLanguages::EMPTY;

    _requestEncoder->enqueue(request.get());
    request.release();

    Uint64 startMilliseconds = TimeValue::getCurrentTime().toMilliseconds();
    Uint64 nowMilliseconds = startMilliseconds;
    Uint64 stopMilliseconds = nowMilliseconds + _timeoutMilliseconds;

    while (nowMilliseconds < stopMilliseconds)
    {
        //
        // Wait until the timeout expires or an event occurs:
        //
        _monitor->run(Uint32(stopMilliseconds - nowMilliseconds));

        //
        // Check to see if incoming queue has a message
        //

        Message* response = dequeue();

        if (response)
        {
            // Shouldn't be any more messages in our queue
            PEGASUS_ASSERT(getCount() == 0);

            //
            // Reconnect to reset the connection
            // if Server response contained a Connection: Close Header
            //
            if (response->getCloseConnect() == true) {
                _reconnect();
                response->setCloseConnect(false);
            }

            //
            //  Future:  If M-POST is used and HTTP response is 501 Not
            //  Implemented or 510 Not Extended, retry with POST method
            //

            if (response->getType() == CLIENT_EXCEPTION_MESSAGE)
            {

                Exception* clientException =
                    ((ClientExceptionMessage*)response)->clientException;
                delete response;

                AutoPtr<Exception> d(clientException);

                // Make the ContentLanguage of the exception available through
                // the CIMClient API (its also available in the exception).
                responseContentLanguages = clientException->getContentLanguages();

                //
                // Determine and throw the specific class of client exception
                //

                CIMClientMalformedHTTPException* malformedHTTPException =
                    dynamic_cast<CIMClientMalformedHTTPException*>(
                        clientException);
                if (malformedHTTPException)
                {
                    throw *malformedHTTPException;
                }

                CIMClientHTTPErrorException* httpErrorException =
                    dynamic_cast<CIMClientHTTPErrorException*>(
                        clientException);
                if (httpErrorException)
                {
                    throw *httpErrorException;
                }

                CIMClientXmlException* xmlException =
                    dynamic_cast<CIMClientXmlException*>(clientException);
                if (xmlException)
                {
                    throw *xmlException;
                }

                CIMClientResponseException* responseException =
                    dynamic_cast<CIMClientResponseException*>(clientException);
                if (responseException)
                {
                    throw *responseException;
                }

                CIMException* cimException =
                    dynamic_cast<CIMException*>(clientException);
                if (cimException)
                {
                    throw *cimException;
                }

                throw *clientException;
            }
            else if (response->getType() == expectedResponseMessageType)
            {
                CIMResponseMessage* cimResponse = (CIMResponseMessage*)response;

                if (cimResponse->messageId != messageId)
                {
                    // l10n

                    // CIMClientResponseException responseException(
                    //   String("Mismatched response message ID:  Got \"") +
                    //    cimResponse->messageId + "\", expected \"" +
                    //    messageId + "\".");

                    MessageLoaderParms mlParms(
                        "Client.CIMClient.MISMATCHED_RESPONSE",
                        "Mismatched response message ID:  Got \"$0\", "
                        "expected \"$1\".",
                        cimResponse->messageId, messageId);
                    String mlString(MessageLoader::getMessage(mlParms));

                    CIMClientResponseException responseException(mlString);

                    delete response;
                    throw responseException;
                }

                // l10n
                // Get the Content-Languages from the response's operationContext
                // and make available through the CIMClient API
                responseContentLanguages =
                    ((ContentLanguageListContainer)cimResponse->operationContext.get
                     (ContentLanguageListContainer::NAME)).getLanguages();

                if (cimResponse->cimException.getCode() != CIM_ERR_SUCCESS)
                {
                    CIMException cimException(
                        cimResponse->cimException.getCode(),
                        cimResponse->cimException.getMessage());
                    cimException.setContentLanguages(responseContentLanguages);
                    delete response;
                    throw cimException;
                }

                /* if excicution gets here everytihng is working correctly and a proper response
                was generated and recived */

                //check that client side statistics are valid before handing them to the
                // client application via a call back
                Boolean re_check = perfDataStore->checkMessageIDandType(cimResponse->messageId,
                                   cimResponse->getType());

                if (re_check && !perfDataStore->getStatError() && perfDataStore->isClassRegistered())
                {
                    //if callback method throws an exception it will be seen by the client
                    //no try/catch block is used here intentionaly - becasue exceptions
                    //come from the client application so client app. should handle them
                    ClientOpPerformanceData item = perfDataStore->createPerfDataStruct();
                    perfDataStore->handler_prt->handleClientOpPerformanceData(item);

                }//end of if statmet that call the callback method
                return response;
            }
            else if (dynamic_cast<CIMRequestMessage*>(response) != 0)
            {
                // Respond to an authentication challenge
                _requestEncoder->enqueue(response);
                nowMilliseconds = TimeValue::getCurrentTime().toMilliseconds();
                stopMilliseconds = nowMilliseconds + _timeoutMilliseconds;
                continue;
            }
            else
            {
                // l10n

                // CIMClientResponseException responseException(
                //   "Mismatched response message type.");
                MessageLoaderParms mlParms(
                    "Client.CIMOperationResponseDecoder.MISMATCHED_RESPONSE_TYPE",
                    "Mismatched response message type.");
                String mlString(MessageLoader::getMessage(mlParms));

                CIMClientResponseException responseException(mlString);

                delete response;
                throw responseException;
            }
        }

        nowMilliseconds = TimeValue::getCurrentTime().toMilliseconds();
        pegasus_yield();
    }

    //
    // Reconnect to reset the connection (disregard late response)
    //
    try
    {
        _reconnect();
    }
    catch (...)
    {
    }

    //
    // Throw timed out exception:
    //
    throw ConnectionTimeoutException();
}
void CIMExportRequestDecoder::handleMethodRequest(
    Uint32 queueId,
    HttpMethod httpMethod,
    char* content,
    const String& requestUri,
    const char* cimProtocolVersionInHeader,
    const char* cimExportMethodInHeader,
    const String& userName,
    const String& ipAddress,
    const AcceptLanguageList& httpAcceptLanguages,
    const ContentLanguageList& httpContentLanguages,
    Boolean closeConnect)
{
    // Set the Accept-Language into the thread for this service.
    // This will allow all code in this thread to get
    // the languages for the messages returned to the client.
    Thread::setLanguages(httpAcceptLanguages);

    //
    // If CIM Listener is shutting down, return error response
    //
    if (_serverTerminating)
    {
        sendHttpError(
            queueId,
            HTTP_STATUS_SERVICEUNAVAILABLE,
            String::EMPTY,
            "CIM Listener is shutting down.",
            closeConnect);
        return;
    }

    // Create a parser:

    XmlParser parser(content);
    XmlEntry entry;
    String messageId;
    const char* cimExportMethodName = "";
    AutoPtr<CIMExportIndicationRequestMessage> request;

    try
    {
        //
        // Process <?xml ... >
        //

        // These values are currently unused
        const char* xmlVersion = 0;
        const char* xmlEncoding = 0;

        XmlReader::getXmlDeclaration(parser, xmlVersion, xmlEncoding);

        // Expect <CIM ...>

        const char* cimVersion = 0;
        const char* dtdVersion = 0;

        XmlReader::getCimStartTag(parser, cimVersion, dtdVersion);

        if (!XmlReader::isSupportedCIMVersion(cimVersion))
        {
            sendHttpError(
                queueId,
                HTTP_STATUS_NOTIMPLEMENTED,
                "unsupported-cim-version",
                String::EMPTY,
                closeConnect);
            return;
        }

        if (!XmlReader::isSupportedDTDVersion(dtdVersion))
        {
            sendHttpError(
                queueId,
                HTTP_STATUS_NOTIMPLEMENTED,
                "unsupported-dtd-version",
                String::EMPTY,
                closeConnect);
            return;
        }

        // Expect <MESSAGE ...>

        String protocolVersion;
        if (!XmlReader::getMessageStartTag(
                    parser, messageId, protocolVersion))
        {
            MessageLoaderParms mlParms(
                "ExportServer.CIMExportRequestDecoder.EXPECTED_MESSAGE_ELEMENT",
                "expected MESSAGE element");

            throw XmlValidationError(parser.getLine(), mlParms);
        }

        // Validate that the protocol version in the header matches the XML

        if (!String::equalNoCase(protocolVersion, cimProtocolVersionInHeader))
        {
            sendHttpError(
                queueId,
                HTTP_STATUS_BADREQUEST,
                "header-mismatch",
                String::EMPTY,
                closeConnect);
            return;
        }

        if (!XmlReader::isSupportedProtocolVersion(protocolVersion))
        {
            // See Specification for CIM Operations over HTTP section 4.3
            sendHttpError(
                queueId,
                HTTP_STATUS_NOTIMPLEMENTED,
                "unsupported-protocol-version",
                String::EMPTY,
                closeConnect);
            return;
        }

        if (XmlReader::testStartTag(parser, entry, "MULTIEXPREQ"))
        {
            // We wouldn't have gotten here if CIMExportBatch header was
            // specified, so this must be indicative of a header mismatch
            sendHttpError(
                queueId,
                HTTP_STATUS_BADREQUEST,
                "header-mismatch",
                String::EMPTY,
                closeConnect);
            return;
            // Future: When MULTIEXPREQ is supported, must ensure
            // CIMExportMethod header is absent, and CIMExportBatch header
            // is present.
        }

        // Expect <SIMPLEEXPREQ ...>

        XmlReader::expectStartTag(parser, entry, "SIMPLEEXPREQ");

        // Expect <EXPMETHODCALL ...>

        if (!XmlReader::getEMethodCallStartTag(parser, cimExportMethodName))
        {
            MessageLoaderParms mlParms(
                "ExportServer.CIMExportRequestDecoder."
                "EXPECTED_EXPMETHODCALL_ELEMENT",
                "expected EXPMETHODCALL element");

            throw XmlValidationError(parser.getLine(), mlParms);
        }

        // The Specification for CIM Operations over HTTP reads:
        //     3.3.9. CIMExportMethod
        //
        //     This header MUST be present in any CIM Export Request
        //     message that contains a Simple Export Request.
        //
        //     It MUST NOT be present in any CIM Export Response message,
        //     nor in any CIM Export Request message that is not a
        //     Simple Export Request. It MUST NOT be present in any CIM
        //     Operation Request or Response message.
        //
        //     The name of the CIM export method within a Simple Export
        //     Request is defined to be the value of the NAME attribute
        //     of the <EXPMETHODCALL> element.
        //
        //     If a CIM Listener receives a CIM Export Request for which
        //     either:
        //
        //     - The CIMExportMethod header is present but has an invalid
        //       value, or;
        //     - The CIMExportMethod header is not present but the Export
        //       Request Message is a Simple Export Request, or;
        //     - The CIMExportMethod header is present but the Export
        //       Request Message is not a Simple Export Request, or;
        //     - The CIMExportMethod header is present, the Export Request
        //       Message is a Simple Export Request, but the CIMIdentifier
        //       value (when unencoded) does not match the unique method
        //       name within the Simple Export Request,
        //
        //     then it MUST fail the request and return a status of
        //     "400 Bad Request" (and MUST include a CIMError header in the
        //     response with a value of header-mismatch), subject to the
        //     considerations specified in Errors.
        if (System::strcasecmp(
                    cimExportMethodName, cimExportMethodInHeader) != 0)
        {
            // ATTN-RK-P3-20020404: How to decode cimExportMethodInHeader?
            sendHttpError(
                queueId,
                HTTP_STATUS_BADREQUEST,
                "header-mismatch",
                String::EMPTY,
                closeConnect);
            return;
        }

        // This try block only catches CIMExceptions, because they must be
        // responded to with a proper EMETHODRESPONSE.  Other exceptions are
        // caught in the outer try block.
        try
        {
            // Delegate to appropriate method to handle:

            if (System::strcasecmp(
                        cimExportMethodName, "ExportIndication") == 0)
            {
                request.reset(decodeExportIndicationRequest(
                                  queueId, parser, messageId, requestUri));
            }
            else
            {
                throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_NOT_SUPPORTED,
                                              MessageLoaderParms(
                                                  "ExportServer.CIMExportRequestDecoder."
                                                  "UNRECOGNIZED_EXPORT_METHOD",
                                                  "Unrecognized export method: $0",
                                                  cimExportMethodName));
            }
        }
        catch (CIMException& e)
        {
            sendEMethodError(
                queueId,
                httpMethod,
                messageId,
                cimExportMethodName,
                e,
                closeConnect);

            return;
        }

        // Expect </EXPMETHODCALL>

        XmlReader::expectEndTag(parser, "EXPMETHODCALL");

        // Expect </SIMPLEEXPREQ>

        XmlReader::expectEndTag(parser, "SIMPLEEXPREQ");

        // Expect </MESSAGE>

        XmlReader::expectEndTag(parser, "MESSAGE");

        // Expect </CIM>

        XmlReader::expectEndTag(parser, "CIM");
    }
    catch (XmlValidationError& e)
    {
        PEG_TRACE((TRC_XML,Tracer::LEVEL1,
                   "CIMExportRequestDecoder::handleMethodRequest - "
                   "XmlValidationError exception has occurred. Message: %s",
                   (const char*) e.getMessage().getCString()));

        sendHttpError(
            queueId,
            HTTP_STATUS_BADREQUEST,
            "request-not-valid",
            e.getMessage(),
            closeConnect);
        return;
    }
    catch (XmlSemanticError& e)
    {
        PEG_TRACE((TRC_XML,Tracer::LEVEL1,
                   "CIMExportRequestDecoder::handleMethodRequest - "
                   "XmlSemanticError exception has occurred. Message: %s",
                   (const char*) e.getMessage().getCString()));
        // ATTN-RK-P2-20020404: Is this the correct response for these errors?
        sendHttpError(
            queueId,
            HTTP_STATUS_BADREQUEST,
            "request-not-valid",
            e.getMessage(),
            closeConnect);
        return;
    }
    catch (XmlException& e)
    {
        PEG_TRACE((TRC_XML,Tracer::LEVEL1,
                   "CIMExportRequestDecoder::handleMethodRequest - "
                   "XmlException has occurred. Message: %s",
                   (const char*) e.getMessage().getCString()));

        sendHttpError(
            queueId,
            HTTP_STATUS_BADREQUEST,
            "request-not-well-formed",
            e.getMessage(),
            closeConnect);
        return;
    }
    catch (Exception& e)
    {
        // Don't know why I got this exception.  Seems like a bad thing.
        // Any exceptions we're expecting should be caught separately and
        // dealt with appropriately.  This is a last resort.
        sendHttpError(
            queueId,
            HTTP_STATUS_INTERNALSERVERERROR,
            String::EMPTY,
            e.getMessage(),
            closeConnect);
        return;
    }
    catch (...)
    {
        // Don't know why I got whatever this is.  Seems like a bad thing.
        // Any exceptions we're expecting should be caught separately and
        // dealt with appropriately.  This is a last resort.
        sendHttpError(
            queueId,
            HTTP_STATUS_INTERNALSERVERERROR,
            String::EMPTY,
            String::EMPTY,
            closeConnect);
        return;
    }

// l10n TODO - might want to move A-L and C-L to Message
// to make this more maintainable
    // Add the language headers to the request.
    // Note: Since the text of an export error response will be ignored
    // by the export client, ignore Accept-Language in the export request.
    // This will cause any export error response message to be sent in the
    // default language.
    request->operationContext.insert(IdentityContainer(userName));
    request->operationContext.set(
        ContentLanguageListContainer(httpContentLanguages));
    request->operationContext.set(
        AcceptLanguageListContainer(AcceptLanguageList()));

    request->ipAddress = ipAddress;

    request->setCloseConnect(closeConnect);

    _outputQueue->enqueue(request.release());
}
// This is only called from SimpleResponseHandler.deliver() but lives in this
// class because all asyncronous response must have a "response" pointer
// to go through. Only operation classes have a response pointer
void OperationResponseHandler::send(Boolean isComplete)
{
	// some handlers do not send async because their callers cannot handle
	// partial responses. If this is the case, stop here.

	if (isAsync() == false)
	{
		// preserve tradional behavior
		if (isComplete == true)
        {
            transfer();
        }

        return;
	}

	SimpleResponseHandler *simpleP = dynamic_cast<SimpleResponseHandler*>(this);

	// It is possible to instantiate this class directly (not derived)
	// The caller would do this only if the operation does not have any data to
	// be returned

	if (! simpleP)
	{
		// if there is no data to be returned, then the message should NEVER be
		// incomplete (even on an error)
		if (isComplete == false)
        {
            PEGASUS_ASSERT(false);
        }

        return;
	}

	SimpleResponseHandler &simple = *simpleP;
	PEGASUS_ASSERT(_response);
	Uint32 objectCount = simple.size();

	// have not reached threshold yet
	if ((isComplete == false) && (objectCount < _responseObjectThreshold))
    {
        return;
    }

	CIMResponseMessage *response = _response;

	// for complete responses, just use the one handed down from caller
	// otherwise, create our own that the caller never sees but is
	// utilized for async responses underneath

	if (isComplete == false)
    {
        _response = _request->buildResponse();
    }

	_response->setComplete(isComplete);
	_responseObjectTotal += objectCount;

	// since we are reusing response for every chunk,keep track of original count
	_response->setIndex(_responseMessageTotal++);

	// set the originally allocated response to one more than the current.
	// The reason for doing this is proactive in case of an exception. This
	// allows the last response to be set as it may not re-enter this code.

	if (isComplete == false)
    {
        response->setIndex(_responseMessageTotal);
    }

	validate();

	if (_response->cimException.getCode() != CIM_ERR_SUCCESS)
    {
        simple.clear();
    }

	String function = getClass() + "::" + "transfer";
	Logger::put(
        Logger::STANDARD_LOG,
        System::CIMSERVER,
        Logger::TRACE,
        function);

	transfer();
	simple.clear();

	// l10n
	_response->operationContext.set(ContentLanguageListContainer(simple.getLanguages()));

	// call thru ProviderManager to get externally declared entry point

	if (isComplete == false)
	{
		ProviderManagerService::handleCimResponse(*_request, *_response);
	}

	// put caller's allocated response back in place. Note that _response
	// is INVALID after sending because it has been deleted externally

	_response = response;
}