Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Connecting to Dynamics 365 for Operations Outbound Using Java

DZone's Guide to

Connecting to Dynamics 365 for Operations Outbound Using Java

Read this tutorial in order to learn how to pull/download a file from Microsoft Dynamics 365.

· Integration Zone ·
Free Resource

How to Transform Your Business in the Digital Age: Learn how organizations are re-architecting their integration strategy with data-driven app integration for true digital transformation.

This is the third and last of the three-part series on connecting to Dynamics 365. We will learn how to pull, or download, a file.

There are 4 steps involved in getting/downloading a file from Dynamics 365.

  • Connect to Dynamics 365 outbound recurring job using the given endpoint. Add bearer token as Authorization Header and get JSON response back (will look something like this):

JSON Response:

{ "CorrelationId": "123e6880-5f64-3762-b713-vdef977dcb21",

"PopReceipt": "XsAAAAMAAAAAAAAAkDwNGjjL0qG=",

"DownloadLocation": "http://abc-sit.sandbox.operations.dynamics.com:80/api/connector/download/b0e4cf1a-1adc-464b-nfd9-14dc6fd697f1?-4f61-8763-m714-edef977dcb20&-7873-4fe1-910d-835df5df0130"

  }
  • Parse JSON response and get "DownloadLocation(D365 URI),” which points to the actual downloadable zip file
  • Replace protocol from HTTP to HTTPS and set the port to 443. Connect to D365 with DownloadLocation and download the file
  • Send acknowledgment back to Dynamics 365

Unfortunately, Mulesoft Connector — Microsoft Dynamics 365 for Operations — doesn’t have “Export data recurring job” Connector Operation. So we will use Java to pull/download the file from Dynamics 365.

First, we need to generate bearer token.

Configuration Details:

abc.activedirectory.@ABC1.onmicrosoft.com

abc.activedirectory.password=***

abc.activedirectory.-02db-4f0c-a143-ad8a0a63cebf

abc.activedirectory.://login.windows.net/ABC1.onmicrosoft.com

abc.activedirectory.://abc-sit.sandbox.operations.dynamics.com

abc.activedirectory.d365DequeuePath=/api/connector/dequeue/1E3A5042-557T-6VF5-CF4R-U2CF9614258X

abc.activedirectory.d365DequeueAcknowledgementPath=/api/connector/ack/1E3A5042-557T-6VF5-CF4R-U2CF9614258X

TokenService and DynamicsFileDownloadService Java Classes:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.naming.ServiceUnavailableException;
import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.aad.adal4j.ClientCredential;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class TokenService {

    private static final Logger LOGGER = LogManager.getLogger(TokenService.class);

    @Value("${abc.activedirectory.userName}")
    private String userName;
    @Value("${abc.activedirectory.password}")
    private String password;
    @Value("${abc.activedirectory.clientId}")
    private String clientId;
    @Value("${abc.activedirectory.authEndPoint}")
    private String authEndPoint;
    @Value("${abc.activedirectory.d365EndPoint}")
    private String d365EndPoint;
    @Value("${abc.activedirectory.d365DequeuePath}")
    private String d365DequeuePath;
    @Value("${abc.activedirectory.d365DequeueAcknowledgementPath}")
    private String d365DequeueAcknowledgementPath;

    public String getAccessToken() throws Exception {

        LOGGER.info("Executing TokenService getAccessToken()");
        AuthenticationContext context = null;
        AuthenticationResult result = null;
        ExecutorService service = null;

        try {
            service = Executors.newFixedThreadPool(1);
            context = new AuthenticationContext(authEndPoint, false, service);
            Future<AuthenticationResult> future = context.acquireToken(d365EndPoint, clientId, userName,
                    password, null);

            result = future.get();

        } finally {
            if (service != null)
                service.shutdown();
        }

        if (result == null) {
            throw new Stage1Exception(errorCodeDynamics,
                    new ServiceUnavailableException("Authentication result was failure"));
        }
        return result.getAccessToken();
    }

    public String getD365EndPoint() {
        return d365EndPoint;
    }

    public String getD365DequeuePath() {
        return d365DequeuePath;
    }

    public String getD365DequeueAcknowledgementPath() {
        return d365DequeueAcknowledgementPath;
    }

}

Now that we have the access token, let's connect to Dynamics 365 to download the file:

public class DynamicsFileDownloadService implements Callable {

    private static final Logger LOGGER = LogManager.getLogger(DynamicsFileDownloadService.class);

    @Autowired
    private TokenService tokenServiceDownload;

    String jsonResponse;
    String d365EndPoint;
    String d365DequeuePath;
    String d365DequeueAcknowledgementPath;
    StringBuilder httpHeader = null;

    public Object onCall(MuleEventContext eventContext) throws Exception {

        LOGGER.info("DynamicsFileDownloadService onCall method executing");
        CloseableHttpClient client = null;
        CloseableHttpResponse response = null;
        ZipInputStream zipInputStream = null;
        HttpEntity jsonEntity = null;
        HttpEntity entity = null;
        HttpGet httpGet = null;
        jsonResponse = null;
        byte[] data = null;
        StringBuilder d365Path = null;
        httpHeader = new StringBuilder();
        Gson gson = new Gson();

        try {

            client = HttpClients.createDefault();

            d365EndPoint = tokenServiceDownload.getD365EndPoint().trim();
            d365DequeuePath = tokenServiceDownload.getD365DequeuePath().trim();

            d365Path = new StringBuilder();
            d365Path.append(d365EndPoint);
            d365Path.append(d365DequeuePath);

            httpHeader.append(ResourceConstants.BEARER);
            httpHeader.append(tokenServiceDownload.getAccessToken().trim());

            // Step 1: Connect to D365 and get Json Response
            httpGet = new HttpGet(d365Path.toString());
            httpGet.addHeader(ResourceConstants.AUTHORIZATION, httpHeader.toString());
            response = client.execute(httpGet);
            jsonEntity = response.getEntity();

            //If the messages in the recurring job are older than 7 days, then we get - "HTTP/1.1 204 No Content" for - response.getStatusLine()
            //HTTP Status 204 (No Content) indicates that the server has successfully fulfilled the request and 
            //that there is no content to send in the response payload body.

            LOGGER.info("Dynamics JSON Response: " + response.getStatusLine());

            if(response.getStatusLine().toString().contains("204")) 
            return data;

            // Step 2: Parse Json Response and get "DownloadLocation(D365 URI)"
            // to download the zip
            jsonResponse = IOUtils.toString(jsonEntity.getContent(), StandardCharsets.UTF_8);
            LOGGER.info("DynamicsFileDownloadService - Received Json Response from Dynamics: " + jsonResponse);
            DynamicsJsonResponseModel dynamicsJsonResponse = gson.fromJson(jsonResponse,
                    DynamicsJsonResponseModel.class);

            // Step 3: Replace protocol to https and port to 443
            String downloadLocation = dynamicsJsonResponse.getDownloadLocation().trim();
            downloadLocation = downloadLocation.replace("http", "https");
            downloadLocation = downloadLocation.replace("80", "443");

            // Step 4: Connect to D365 with DownloadLocation and download the
            // zip file
            httpGet = new HttpGet(downloadLocation);
            httpGet.addHeader(ResourceConstants.AUTHORIZATION, httpHeader.toString());
            response = client.execute(httpGet);
            entity = response.getEntity();

            zipInputStream = new ZipInputStream(entity.getContent());

            if (zipInputStream != null)
                LOGGER.info("DynamicsFileDownloadService - Downloaded payload from Dynamics: ");

            // Step 5: Created zipInputStream from the downloaded zip file and passing it to unzip
            data = unzip(zipInputStream, eventContext);

            // Step 6: Send Acknowledgement back to Dynamics
            sendAcknowledgement();

        } catch (Exception exception) {
            LOGGER.error("Exception in DynamicsFileDownloadService: " + exception.getMessage());
        } finally {
                if (httpGet != null)
                    httpGet.abort();

                if (response != null)
                    response.close();

                if (client != null)
                    client.close();
        }
        return data;
    }

I hope you enjoyed reading this article. I'm looking forward to your comments and feedback.

Make your mark on the industry’s leading annual report. Fill out the State of API Integration 2019 Survey and receive $25 to the Cloud Elements store.

Topics:
dynamics 365 ,java ,mule ,integration ,json ,configuration

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}