CRM - Microsoft Dynamics

  • Posted on: 3 February 2017
  • By: vinodkumartiwari

A Cloud based Customer Relationship Management(CRM) software package developed by Microsoft. Microsoft Dynamics CRM is cloud based server-client application, which provides RESTful endpoint to access different CRM entities, which is primarily an IIS based web application.

Here we are going to provide an overview on how to consume the RESTful endpoint for various Microsoft Dynamics CRM to access the CRM resources. The implementation is based on Java technology. This demonstration is based on the following dependencies which is managed through the Gradle:

So let's begin toward building a web client consuming the Microsoft Dynamics CRM RESTful endpoints and displaying the CRM data.

Problem: Develop a Java based implementation for web client to connect with Microsoft Dynamics CRM and display CRM data.

Solution: Here you need to create a Gradle project using Eclipse IDE. Gradle will manage all the required dependencies in the project for various libraries needed including Microsoft Azure. Focus on the steps below to create a fresh web client and connect with the Microsoft Dynamics CRM. We are considering you already have an account registered with Microsoft Dynamics CRM if not try registering for a trial version and pass the required configurations in Java constants class.

Step 1: Create a Gradle project with and add the classes shown below in the project structure

dynamics crm web client structure

Step 2: Let's add required dependencies with build.gradle

dependencies {
compile group: 'org.slf4j', name : 'slf4j-api' version : '1.7.21'
compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.8.5'
compile group: 'org.codehaus.jackson', name: 'jackson-mapper-asl', version: '1.5.0'
compile group: 'com.sun.jersey', name: 'jersey-client', version: '1.19.1'
compile group: 'com.sun.jersey', name: 'jersey-json', version: '1.19.1'
compile group: 'javax.ws.rs', name: 'javax.ws.rs-api', version: '2.0'
compile group: 'com.sun.jersey', name: 'jersey-servlet', version: '1.19.1'
compile group: 'com.microsoft.azure', name: 'adal4j', version: '0.0.3'
testCompile 'junit:junit:4.12'
}
Step 3: Set the valid Microsoft Dynamics CRM configurations to the Java class to read and connect in AppConstants.java
package com.demo.dynamics.crm;

public class AppConstants {
  public final static String CLIENT_ID = "xxxxx-xxxx-xxxx-xxxx-xxxxx";
  public final static String RESOURCE = "https://xxxx.xxxx.dynamics.com/";
  public final static String USERNAME = "admin@xxxx.onmicrosoft.com";
  public final static String PASSWORD = "xx$xx";
  public final static String DISCOVERY_URL = "https://xxxx.crm4.dynamics.com/api/data/v8.1/";
  public final static String CLIENT_SECRET = "xx+xx/xxxxxxxxxxxxxxxxxxxxxxxxxxxxx=";
  public static final String TOKEN_URL = "https://login.microsoftonline.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/oauth2/token";
  public static final String GRANT_TYPE = "password";
}
Step 4: Now we have the valid CRM configurations so now try obtaining a valid token using Java class with the implementation in TokenManager.java
package com.demo.dynamics.crm.rest.client;

/**
 * Token Manager will return the access token and refresh token
 */
public class TokenManager {
  private static Logger LOG = LoggerFactory.getLogger(TokenManager.class);
  private Client client;
  private ClientConfig clientConfig;

  public TokenManager() {
    this.clientConfig = new DefaultClientConfig();
    clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
    this.client = Client.create(clientConfig);
  }

  /**
   * Builds the access token
   *
   * @return access token
   * @throws Exception
   */
  public JwtToken getAccessToken() throws Exception {
    Form form = new Form();
    ClientResponse response = null;
    WebResource webResource = null;

    try {
      form.add("grant_type", AppConstants.GRANT_TYPE);
      form.add("username", AppConstants.USERNAME);
      form.add("password", AppConstants.PASSWORD);
      form.add("resource", AppConstants.RESOURCE);
      form.add("client_id", AppConstants.CLIENT_ID);
      form.add("client_secret", AppConstants.CLIENT_SECRET);
      webResource = client.resource(TOKEN_URL);
      response = webResource.accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_FORM_URLENCODED_TYPE)
          .post(ClientResponse.class, form);

      if (response.getStatus() == 200) {
        JwtToken token = response.getEntity(JwtToken.class);
        return token;
      } else {
        String responseBody = response.getEntity(String.class);
        throw new CrmClientException(
            "Error fetching jwt: " + response.getStatus() + " " + response.getStatusInfo() + " : " + responseBody);
      }

    } catch (Exception e) {
      throw new CrmClientException("Unable to obtain token", e);
    }
  }
}

Step 5: After obtaining a valid JWT token to make a request create a client AbstractCrmClient.java which will help you creating multiple client for various entities

package com.demo.dynamics.crm.rest.client;

public abstract class AbstractCrmClient {
  protected final JwtToken jwtToken;
  protected final Client client;

  public AbstractCrmClient(JwtToken jwtToken) {
    this.jwtToken = jwtToken;

    ClientConfig clientConfig = new DefaultClientConfig();
    clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
    this.client = Client.create(clientConfig);
  }
}

Step 6: Now create a sample Dynamics CRM client with DynamicsCrmClient.java which will extends AbstractCrmClient.java

package com.demo.dynamics.crm.rest.client;

public class DynamicsCrmClient extends AbstractCrmClient {
  private static final String WHOAMI = "WhoAmI";

  public DynamicsCrmClient(JwtToken jwtToken) {
    super(jwtToken);
  }

  public DynamicsCrm CrmConnect() {
    String uri = AppConstants.DISCOVERY_URL + WHOAMI;
    WebResource webResource = client.resource(uri);

    try {
      ClientResponse clientResponse = webResource.header("Authorization", "Bearer " + jwtToken.getAccessToken())
          .type(MediaType.APPLICATION_JSON).get(ClientResponse.class);

      if (clientResponse.getStatus() == 200) {
        CrmEntity entity = clientResponse.getEntity(new GenericType>() {});
        return entity.getValue();
      } else {
        String jsonResponse = clientResponse.getEntity(String.class);
        throw new CrmClientException("Unexpected response: " + clientResponse.getStatus() + " "
            + clientResponse.getStatusInfo() + " " + jsonResponse);
      }
    } catch (Exception e) {
      throw new Exception("Unable to connect with Dynamics CRM.");
    }
  }
}

Step 7: We have used a POJO/model called DynamicsCRM.java

package com.demo.dynamics.crm.rest.model;

import com.fasterxml.jackson.annotation.JsonProperty;

/**
 * CRM model to capture WhoAmI
 */
public class DynamicsCrm {
  @JsonProperty(value = "BusinessUnitId")
  private String businessUnitId;

  // the system user ID for the currently logged on user
  @JsonProperty(value = "UserId")
  private String systemUserId;

  public String getBusinessUnitId() {
    return businessUnitId;
  }

  public void setBusinessUnitId(String businessUnitId) {
    this.businessUnitId = businessUnitId;
  }

  public String getSystemUserId() {
    return systemUserId;
  }

  public void setSystemUserId(String systemUserId) {
    this.systemUserId = systemUserId;
  }

  public String getOrganizationId() {
    return organizationId;
  }

  public void setOrganizationId(String organizationId) {
    this.organizationId = organizationId;
  }

  @JsonProperty(value = "OrganizationId")
  private String organizationId;
}

Step 8: Also we have used a POJO/model for JWT token JwtToken.java

package com.demo.dynamics.crm.rest.model;

@JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY)
public class JwtToken {

  @JsonProperty(value = "token_type")
  private String tokenType;

  @JsonProperty(value = "expires_in")
  private int expiresIn;

  @JsonProperty(value = "ext_expires_in")
  private int extExpiresIn;

  @JsonProperty(value = "expires_on")
  private int expiresOn;

  @JsonProperty(value = "not_before")
  private long notBefore;

  @JsonProperty(value = "refresh_token")
  private String refreshToken;

  @JsonProperty(value = "scope")
  private String scope;

  @JsonProperty(value = "resource")
  private String resource;

  @JsonProperty(value = "access_token")
  private String accessToken;

  public String getTokenType() {
    return tokenType;
  }

  public void setTokenType(String tokenType) {
    this.tokenType = tokenType;
  }

  public int getExpiresIn() {
    return expiresIn;
  }

  public void setExpiresIn(int expiresIn) {
    this.expiresIn = expiresIn;
  }

  public int getExtExpiresIn() {
    return extExpiresIn;
  }

  public void setExtExpiresIn(int extExpiresIn) {
    this.extExpiresIn = extExpiresIn;
  }

  public int getExpiresOn() {
    return expiresOn;
  }

  public void setExpiresOn(int expiresOn) {
    this.expiresOn = expiresOn;
  }

  public long getNotBefore() {
    return notBefore;
  }

  public void setNotBefore(long notBefore) {
    this.notBefore = notBefore;
  }

  public String getRefreshToken() {
    return refreshToken;
  }

  public void setRefreshToken(String refreshToken) {
    this.refreshToken = refreshToken;
  }

  public String getScope() {
    return scope;
  }

  public void setScope(String scope) {
    this.scope = scope;
  }

  public String getResource() {
    return resource;
  }

  public void setResource(String resource) {
    this.resource = resource;
  }

  public String getAccessToken() {
    return accessToken;
  }

  public void setAccessToken(String accessToken) {
    this.accessToken = accessToken;
  }
}

Step 9: Finally I have created a Main class to test the Dyanmics CRM web client and print the result on console.

/**
 * Main class to test the GET Dynamics CRM requests
 */
public class Main {
  private static Logger LOG = LoggerFactory.getLogger(Main.class);

  public static void main(String[] args) throws Exception {
    // getting access token using user credentials
    JwtToken jwtToken = new TokenManager().getAccessToken();
    DynamicsCrm crm = new DynamicsCrmClient(jwtToken).CrmConnect();

    LOG.info("CRM connection Test: CRM with BusinessUnitId" + crm.getBusinessUnitId().toString() + "and OrganizationId "
        + crm.getOrganizationId().toString() + "working fine.");
  }
}

Hope the above sample implementation helping you in development your Dynamics Web Client solutions. If you have any queries or suggestions for me feel free to reach me out hello@vaacom.com .

Applyig Filter on Dynamics CRM System Query Using Open Data Protocal (OData) Endpoint

Microsoft Dynamics CRM using Odata System Query option to retrieve data collection for the different entities. The endpoint to retrieve the collection of data from an entity in Microsoft Dynamics CRM the URI with $filter identifier is being used to apply filtering any CRM entity.

The syntax will be like:

	{crm resource uri}/{odata base}/endpoint?$filter={function}(filter critaria using operators)

Description: 1. {crm resource uri}: A valid and active Dynamics CRM resource path like https://xxxx.dynamics.com 2. {odata base}: OData base fragment of URI needs to suffix '/api/data/v8.1'. 3. endpoint: The entity endpoint we need to fetch and request the entity collection. 4. $filter: Keyword to Filter System Query Option in OData 5. function: Dynamics CRM support following function to apply filter critaria using operators 5.1: startwith 5.2: substringof 5.3: endwith 6. {operator}: Dynamics CRM provides and support various operators listed below: 6.1: eq (Equals) 6.2: ne (Not Equals) 6.3: gt (Greater Than) 6.4: lt (Less Than) 6.4: ge (Greater Than or Equals) 6.5: le (Less Than or Equals) 6.6: not (Negation) 6.7: and (Logical And) 6.8: or (Logical Or)

So after applying of all the above points we can create a sample endpoint for the user entity using system query for open data protocal $filter:

https://xxxx.dynamics.com/systemusers?$filter=endswith(internalemailaddress, '@xxxxx.onmicrosoft.com')

After requesting this endpoint for systemusers and applying the critaria on internalemailaddress field we can fetch the filtered collection. Feel free to raise any question of submit your suggestion to improve this artical. Contact us on hello@vaacom.com.