Advanced Service Sample

Prior to running this sample make sure you have completed the samples configuration step (Samples Configuration).

This sample differs from the Basic Service Sample by breaking the "service provider" and "service invoker" functionality into two distinct scripts. When executed, each of these scripts will contain a unique instance of a dxlclient.client.DxlClient.

Service Provider

The first step is to start the "service provider". This script will remain running and receive dxlclient.message.Request messages from the "service invoker".

To start the "service provider", execute the sample\advanced\service_provider_sample.py script as follows:

c:\dxlclient-python-sdk-5.6.0.4>python sample\advanced\service_provider_sample.py

The output should appear similar to the following:

2015-12-30 10:25:32,168 __main__ - INFO - Service Provider - Load DXL config from: c:dxlclient-python-sdk-5.6.0.4\sample/dxlclient.config
2015-12-30 10:25:32,170 __main__ - INFO - Service Provider - Creating DXL Client
2015-12-30 10:25:32,187 __main__ - INFO - Service Provider - Connecting to Broker
2015-12-30 10:25:32,187 dxlclient.client - INFO - Waiting for broker list...
2015-12-30 10:25:32,188 dxlclient.client - INFO - Checking brokers...
2015-12-30 10:25:32,190 dxlclient.client - INFO - Trying to connect...
2015-12-30 10:25:32,190 dxlclient.client - INFO - Trying to connect to broker {Unique id: mybroker, Host name: mybroker.mcafee.com, IP address: 10.84.221.144, Port: 8883}...
2015-12-30 10:25:32,457 dxlclient.client - INFO - Connected to broker mybroker
2015-12-30 10:25:32,459 dxlclient.client - INFO - Launching event loop...
2015-12-30 10:25:32,459 dxlclient.client - INFO - Connected with result code 0
2015-12-30 10:25:32,460 dxlclient.client - INFO - Subscribing to /mcafee/client/{1b53cd6a-5829-4a76-a913-a120dc59ede7}
2015-12-30 10:25:32,461 __main__ - INFO - Registering service.
2015-12-30 10:25:32,463 dxlclient.client - INFO - Message received for topic /mcafee/client/{1b53cd6a-5829-4a76-a913-a120dc59ede7}
   Enter 9 to quit
   Enter value:

The provider will remain running until 9 is entered to quit.

Any dxlclient.message.Request messages received by the "service invoker" will be displayed in the output.

The code for the provider is very similar to what is being used in the Basic Service Sample:

# Response callback class to handle DXL Responses to our Asynchronous Requests
class MyRequestCallback(RequestCallback):
    def on_request(self, request):
        # Extract information from Response payload, in this sample we expect it is UTF-8 encoded
        logger.info("Service Provider - Request received:\n   Topic: %s\n   Request ID: %s\n   Payload: %s",
                    request.destination_topic,
                    request.message_id,
                    request.payload.decode())

        # Create the Response message
        logger.info("Service Provider - Creating Response for Request ID %s on %s",
                    request.message_id, request.destination_topic)
        response = Response(request)

        # Encode string payload as UTF-8
        response.payload = "Sample Response Payload".encode()

        # Send the Response back
        logger.info("Service Provider - Sending Response to Request ID: %s on %s",
                    response.request_message_id, request.destination_topic)
        client.send_response(response)

# Create DXL Service Registration object
service_registration_info = ServiceRegistrationInfo(client, "/mycompany/myservice")

# Add a topic for the service to respond to
service_registration_info.add_topic(SERVICE_TOPIC, MyRequestCallback())

# Register the service with the DXL fabric (with a wait up to 10 seconds for registration to complete)
logger.info("Registering service.")
client.register_service_sync(service_registration_info, 10)

A dxlclient.callbacks.RequestCallback is constructed that will be invoked for a specific topic associated with the service. The callback will send back a dxlclient.message.Response for any dxlclient.message.Request messages that are received.

It then creates a dxlclient.service.ServiceRegistrationInfo instance and registers the request callback with it via the dxlclient.service.ServiceRegistrationInfo.add_topic() method.

Finally it registers the service with the fabric via the dxlclient.client.DxlClient.register_service_sync() method of the dxlclient.client.DxlClient.

Service Invoker

The next step is to start the "service invoker". This script must be executed in a separate command prompt (or shell), leaving the "service provider" running.

To start the "service invoker", execute the sample\advanced\service_invoker_sample.py script as follows:

c:\dxlclient-python-sdk-5.6.0.4>python sample\advanced\service_invoker_sample.py

The output should appear similar to the following:

2015-12-30 10:43:33,627 __main__ - INFO - Service Invoker - Load DXL config from: c:\dxlclient-python-sdk-5.6.0.4\sample/dxlclient.config
2015-12-30 10:43:33,628 __main__ - INFO - Service Invoker - Creating DXL Client
2015-12-30 10:43:33,644 __main__ - INFO - Service Invoker - Connecting to Broker
2015-12-30 10:43:33,645 dxlclient.client - INFO - Waiting for broker list...
2015-12-30 10:43:33,645 dxlclient.client - INFO - Checking brokers...
2015-12-30 10:43:33,648 dxlclient.client - INFO - Trying to connect...
2015-12-30 10:43:33,648 dxlclient.client - INFO - Trying to connect to broker {Unique id: mybroker, Host name: mybroker.mcafee.com, IP address: 10.84.221.144, Port: 8883}...
2015-12-30 10:43:33,917 dxlclient.client - INFO - Connected to broker mybroker
2015-12-30 10:43:33,918 dxlclient.client - INFO - Launching event loop...
2015-12-30 10:43:33,920 dxlclient.client - INFO - Connected with result code 0
2015-12-30 10:43:33,920 dxlclient.client - INFO - Subscribing to /mcafee/client/{9ee95507-0c73-4696-a628-6a89e2a79194}
   Press 1 to send a Synchronous Request
   Press 2 to send an Asynchronous Request
   Press 9 to quit
   Enter value:

To publish a synchronous dxlclient.message.Request message, enter 1.

To publish an asynchronous dxlclient.message.Request message, enter 2.

Information similar to the following should appear in the "service provider" output indicating that the dxlclient.message.Request message was properly received and that a corresponding dxlclient.message.Response message was sent:

2015-12-30 10:44:59,832 __main__ - INFO - Service Provider - Request received:
   Topic: /isecg/sample/service
   Request ID: {0e7c1994-b610-4436-ae3b-e2eec9ebdf33}
   Payload: Sample Synchronous Request Payload - Request ID: {0e7c1994-b610-4436-ae3b-e2eec9ebdf33}
2015-12-30 10:44:59,834 __main__ - INFO - Service Provider - Creating Response for Request ID {0e7c1994-b610-4436-ae3b-e2eec9ebdf33} on /isecg/sample/service
2015-12-30 10:44:59,835 __main__ - INFO - Service Provider - Sending Response to Request ID: {0e7c1994-b610-4436-ae3b-e2eec9ebdf33} on /isecg/sample/service

Information similar to the following should appear in the "service invoker" output indicating that the dxlclient.message.Response message was properly received:

2015-12-30 10:44:59,838 dxlclient.client - INFO - Message received for topic /mcafee/client/{9ee95507-0c73-4696-a628-6a89e2a79194}
2015-12-30 10:44:59,845 __main__ - INFO - Service Invoker - Synchronous Response received:
   Topic: /mcafee/client/{9ee95507-0c73-4696-a628-6a89e2a79194}
   Payload: Sample Response Payload

The code for making synchronous requests is very similar to what is being used in the Basic Service Sample:

logger.info(
    "Service Invoker - Creating Synchronous Request for topic %s",
    SERVICE_TOPIC)
request = Request(SERVICE_TOPIC)

# Encode string payload as UTF-8
request.payload = \
    ("Sample Synchronous Request Payload - Request ID: " +
     str(request.message_id)).encode()

# Send Synchronous Request with default timeout and wait for Response
logger.info(
    "Service Invoker - Sending Synchronous Request to %s",
    SERVICE_TOPIC)
response = client.sync_request(request)

# Check that the Response is not an Error Response, then extract
if response.message_type != Message.MESSAGE_TYPE_ERROR:
    # Extract information from Response payload, in this sample
    # we expect it is UTF-8 encoded
    logger.info(
        "Service Invoker - Synchronous Response received:\n" +
        "   Topic: %s\n   Payload: %s",
        response.destination_topic,
        response.payload.decode())
else:
    logger.info(
        "Service Invoker - Synchronous Error Response received:\n" +
        "   Topic: %s\n   Error: %s",
        response.destination_topic, response.error_message)

A dxlclient.message.Request message is constructed and a payload is assigned. The dxlclient.client.DxlClient.sync_request() method of the dxlclient.client.DxlClient is invoked which delivers the request message to the fabric. The dxlclient.message.Response message is checked to ensure it is not an error, and its payload is displayed.

The code for making asynchronous requests is listed below:

# Response callback class to handle DXL Responses from a Service to our Asynchronous Requests
class MyResponseCallback(ResponseCallback):
    def on_response(self, response):
        # Check that the Response is not an Error Response,
        # then extract
        if response.message_type != Message.MESSAGE_TYPE_ERROR:
            # Extract information from Response payload, in this
            # sample we expect it is UTF-8 encoded
            logger.info(
                "Service Invoker - " +
                "Asynchronous Response received:\n   " +
                "Topic: %s\n   Request ID: %s\n   Payload: %s",
                response.destination_topic,
                response.request_message_id,
                response.payload.decode())
        else:
            logger.info(
                "Service Invoker - " +
                "Asynchronous Error Response received:\n   " +
                "Topic: %s\n   Request ID: %s\n   Error: %s",
                response.destination_topic,
                response.request_message_id,
                response.error_message)

# Create the Request
logger.info(
    "Service Invoker - " +
    "Creating Asynchronous Request for topic %s", SERVICE_TOPIC)
request = Request(SERVICE_TOPIC)

# Encode string payload as UTF-8
request.payload = 'Sample Asynchronous Request Payload'.encode()

#Send Asynchronous Request with a timeout of 5 seconds
logger.info(
    "Service Invoker - Sending Asynchronous Request:\n   " +
    "Request ID: %s\n   Topic: %s",
    request.message_id, SERVICE_TOPIC)
client.async_request(request, MyResponseCallback())

A dxlclient.callbacks.ResponseCallback is defined that will receive the dxlclient.message.Response message from the service provider. The callback will display the details of the response message that was received (including validating that it is not an error response).

A dxlclient.message.Request message is constructed and a payload is assigned. The dxlclient.client.DxlClient.async_request() method of the dxlclient.client.DxlClient is invoked which delivers the request message to the fabric. Along with the request, an instance of the previously defined response callback is included which will be invoked when a response is received from the service provider.