Custom Change Management System

FlexDeploy has out of box integration with ServiceNow, but you can easily integrate with other change management systems. Such third party Change Management System integration can be enabled using Java or Groovy implementation.

Go to Change Management Systems page using Administration - Integrations - Change Management Systems menu.

Let's look at more details on how to create a custom change management system integration with Flex Deploy. Click Create to implement integration with custom change management system.

  • Provide a unique name and description
  • Define properties for the new change management system. Properties are configuration values used by FlexDeploy to connect to the new system.
    • If you define properties, you can indicate display and validation details. You can also indicate if property is required and/or encrypted.
    • Enter a unique Name before adding any properties
  • Provide either Java Implementation or Groovy API.
  • Click Save.

Let's define an example change management system in FlexDeploy. You can provide implementation as Java class or just Groovy script. Groovy script would allow for dynamic update whereas use of Java code will require restart of server.

Here we are creating custom change management system with the properties, you can add more as necessary.

API Implementation

Implementation must implement the following API operations to integrate with FlexDeploy.

Method Name

Parameter(s)
Return Type

Description

createRequest

String pDescription, String pCommentvoid

Creates a Change Request ticket using the pDescription and pComment

createIncident

String pDescription, String pCommentString

Creates an Incident ticket using the pDescription and pComment

findRequestByType

String pRequestNumber, RequestType pRequestTypevoid

Find a Change Request using the request number and type. Custome CMS services should cast other types like QUESTION, PROBLEM to pRequestType when returning the matching Request object

Note : FlexDeploy supports the following RequestType enum

REQUEST - Use if the ticket is a change request

INCIDENT - Use if the ticket is an incident due to any failure in an env

OTHER - If the ticket doesn't fall in the above two categories

isRequestApproved

String pRequestNumber, String pEnvironmentCodevoid

Checks if the given change request number (pRequestNumber) is approved in the environment (pEnvironmentCode)

isRequestRejected

String pRequestNumber, String pEnvironmentCodeStringChecks if the given change request number (pRequestNumber) is rejected in the environment (pEnvironmentCode)

checkConnection


void

This should invoke any status or heath check URL of the change management system to ensure the system is up and running

isDoPolling


void

Return flag true or false.

Disable automatic polling (every minute) of change management tickets for status changes.

Java Implementation

Here are high level steps for Java implementation. You can use any IDE to prepare this implementation. 

  • Create java class that extends flexagon.fd.model.integration.cms.api.ChangeManagementSystem. Example shown below has the methods implemented which uses properties map to retrieve the configuration values to connect to the change management system.
  • All properties defined are available in Map returned by getProperties method.
  • We are using Zendesk as a usecase
Example class ZendeskServiceIntegration
package mycompany.extension.flexdeploy.zendesk;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.filter.LoggingFilter;

import flexagon.fd.model.integration.cms.api.ChangeManagementSystem;
import flexagon.fd.model.integration.cms.api.Request;
import flexagon.fd.model.integration.util.ApiException;

import java.io.Serializable;
import java.io.StringReader;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.json.JsonReader;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

public class ZendeskServiceIntegration
  extends ChangeManagementSystem
{
  private static final String CLZ_NAM = ZendeskServiceIntegration.class.getName();
  private Client mRestClient;
  private String mAccessToken;
  private Logger mLogger;

  public ZendeskServiceIntegration()
  {
    super();
    this.mLogger = Logger.getLogger(CLZ_NAM);
  }

  private void getOAuthAccessToken(String pScope)
    throws ApiException
  {
    JsonObjectBuilder zenOAuthRequestJson = Json.createObjectBuilder();
    zenOAuthRequestJson.add("grant_type", "password");
    zenOAuthRequestJson.add("client_id", getClientId());
    zenOAuthRequestJson.add("client_secret", getClientSecret());
    zenOAuthRequestJson.add("username", getUserName());
    zenOAuthRequestJson.add("password", getPassword());
    zenOAuthRequestJson.add("scope", pScope);
    String payLoad = zenOAuthRequestJson.build().toString();
    ClientResponse clientResponse =
      getRestClient().resource(getZendeskDomain()).path(getOAuthURI()).accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).post(ClientResponse.class, payLoad);
    checkResponse(clientResponse);
    JsonObject jsonResponseObject = readJsonObject(clientResponse.getEntity(String.class));
    print("OAuth Response " + jsonResponseObject);
    mAccessToken = jsonResponseObject.getString("access_token");
  }

  private String getAccessToken(String pScope)
    throws ApiException
  {
    getOAuthAccessToken(pScope);
    return "Bearer " + mAccessToken;
  }

  private String getOAuthURI()
  {
    return getPropertyAsString("ZD_OAUTH_URI");
  }

  private String getClientId()
  {
    return getPropertyAsString("ZD_CLIENT_ID");
  }

  private String getClientSecret()
  {
    return getPropertyAsString("ZD_CLIENT_SECRET");
  }

  @Override
  public Request createRequest(String pDescription, String pComment)
    throws ApiException
  {
    String methodName = "createRequest";
    print(methodName + String.format(" Creating new Request using the description [%s] and comment[%s]", pDescription, pComment));
    return postTicket("request", "ZD_REQUEST_CREATE_PATTERN", "question", pDescription, pComment, "requests:write read");
  }

  private Request postTicket(String pObjectType, String pURLKey, String pTicketType, String pDescription, String pComment, String pScope)
    throws ApiException
  {
    String methodName = "postTicket";
    print(methodName + String.format(" Creating new Request using the description [%s] and comment[%s]", pDescription, pComment));
    JsonObjectBuilder zenInputJson = Json.createObjectBuilder();
    JsonObjectBuilder inputParamJsonBuider = Json.createObjectBuilder();
    inputParamJsonBuider.add("subject", pDescription);
    JsonObjectBuilder descriptionJsonBuider = Json.createObjectBuilder();
    descriptionJsonBuider.add("body", pComment);
    inputParamJsonBuider.add("comment", descriptionJsonBuider.build());
    inputParamJsonBuider.add("type", pTicketType);
    zenInputJson.add(pObjectType, inputParamJsonBuider.build());

    WebResource postRequest = getWebResource(getPropertyAsString(pURLKey));
    String payLoad = zenInputJson.build().toString();
    print(methodName + String.format(" Creating new %s %s", pObjectType, payLoad));
    ClientResponse clientResponse =
      postRequest.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).header("Authorization", getAccessToken(pScope)).post(ClientResponse.class, payLoad);
    checkResponse(clientResponse);
    JsonObject jsonResponseObject = readJsonObject(clientResponse.getEntity(String.class));
    JsonObject requestResponseJson = jsonResponseObject.getJsonObject(pObjectType);
    RequestImpl request =
      new RequestImpl(String.valueOf(requestResponseJson.getInt("id")), requestResponseJson.getString("description"), requestResponseJson.getString("status"), requestResponseJson.getString("type"),
                      true, requestResponseJson);
    print(methodName + String.format(" Successfully created ticket %s", request.getNumber()));
    return request;
  }

  private JsonObject readJsonObject(String source)
  {
    String methodName = "readJsonObject";
    JsonReader jsonReader = Json.createReader(new StringReader(source));
    JsonObject object = null;
    try
    {
      object = jsonReader.readObject();
      print(methodName + String.format(" Json object created for response = %s", source));
    }
    catch (Exception e)
    {
      mLogger.logp(Level.INFO, mLogger.getName(), methodName, String.format(" Exception while creating response json object, error %s, response = %s", e.getMessage(), source), e);
    }
    finally
    {
      if (jsonReader != null)
      {
        jsonReader.close();
      }
    }

    return object;
  }

  @Override
  public Request createIncident(String pDescription, String pComment)
  {
    String methodName = "createIncident";
    Request request = null;
    try
    {
      request = postTicket("ticket", "ZD_TICKET_CREATE_PATTERN", "incident", pDescription, pComment, "tickets:write read");
    }
    catch (ApiException e)
    {
      mLogger.logp(Level.INFO, mLogger.getName(), methodName, String.format(" Exception while creating incident, error %s", e.getMessage()), e);
    }
    return request;
  }

  @Override
  public Request findRequestByType(String pRequestNumber, ChangeManagementSystem.RequestType pRequestType)
    throws ApiException
  {
    Request changeRequest = getChangeRequest(pRequestNumber);
    if (changeRequest != null && changeRequest.getTypeName().equalsIgnoreCase("QUESTION") && pRequestType.equals(ChangeManagementSystem.RequestType.REQUEST))
    {
      print(pRequestNumber + " is of type QUESTION, setting it as REQUEST for FD");
      ((RequestImpl) changeRequest).setType(ChangeManagementSystem.RequestType.REQUEST.name());
    }
    return getChangeRequest(pRequestNumber);
  }

  private Request getChangeRequest(String pRequestNumber)
    throws ApiException
  {
    return getTicket("request", "ZD_REQUEST_GET_PATTERN", pRequestNumber, "{ZENDESK_REQUEST}");
  }


  private Request getTicket(String pObjectType, String pURLKey, String pRequestNumber, String pSearchPattern)
    throws ApiException
  {
    String methodName = "getTicket";
    print(methodName + String.format(" Find Ticket [%s] ", pRequestNumber));

    //Zendesk Get Request URL Pattern (/api/v2/requests/{ZENDESK_REQUEST}.json)
    String urlString = getPropertyAsString(pURLKey);
    urlString = urlString.replace(pSearchPattern, pRequestNumber);
    ClientResponse clientResponse = getWebResource(urlString).header("Authorization", getAccessToken("tickets:write read")).get(ClientResponse.class);
    checkResponse(clientResponse);
    JsonObject jsonResponseObject = readJsonObject(clientResponse.getEntity(String.class));
    JsonObject ticketResponseJson = jsonResponseObject.getJsonObject(pObjectType);
    RequestImpl request =
      new RequestImpl(String.valueOf(ticketResponseJson.getInt("id")), ticketResponseJson.getString("description"), ticketResponseJson.getString("status"), ticketResponseJson.getString("type"), true,
                      ticketResponseJson);
    print(methodName + String.format(" Successfully found ticket %s", request.getNumber()));
    return request;
  }

  @Override
  public Boolean isRequestApproved(String requestNumber, String environmentCode)
  {
    Request findRequest = null;
    Boolean approved = false;
    try
    {
      findRequest = getChangeRequest(requestNumber);
      if (findRequest != null)
      {
        String status = findRequest.getStatus();
        print(String.format("#[%s] status [%s]", requestNumber, status));
        if ("solved".equalsIgnoreCase(status))
        {
          approved = true;
        }
      }
    }
    catch (Exception e)
    {
      mLogger.logp(Level.INFO, mLogger.getName(), "isRequestApproved", "Unable to check the status, failed - " + e.getMessage(), e);
    }
    return approved;
  }


  @Override
  public Boolean isRequestRejected(String requestNumber, String environmentCode)
  {
    Request findRequest = null;
    Boolean rejected = false;
    try
    {
      findRequest = getChangeRequest(requestNumber);
      if (findRequest != null)
      {
        String status = findRequest.getStatus();
        print(String.format("#[%s] status [%s]", requestNumber, status));
        if ((!"New".equalsIgnoreCase(status)) && ("on-hold".equalsIgnoreCase(status) || "Closed".equalsIgnoreCase(status)))
        {
          rejected = true;
        }
      }
    }
    catch (Exception e)
    {
      mLogger.logp(Level.INFO, mLogger.getName(), "isRequestRejected", "Unable to check the status, failed - " + e.getMessage(), e);
    }
    return rejected;
  }

  @Override
  public Boolean isDoPolling()
  {
    return false;
  }

  @Override
  public void checkConnection()
    throws ApiException
  {
    String methodName = "checkConnection";
    print(methodName + " getting user details to check connection");
    ClientResponse clientResponse = getWebResource("/api/v2/users/me.json").header("Authorization", getAccessToken("organizations:write read")).get(ClientResponse.class);
    checkResponse(clientResponse);
    print(methodName + " Test connection response code looks valid, check content of response");
    String responseString = clientResponse.getEntity(String.class);
    print(methodName + "responseString=" + responseString + ", Validated that JSON data was received from test connction URL invocation.");
  }

  private StringBuilder getZendeskURLBuilder()
  {
    StringBuilder urlBuilder = new StringBuilder(getPropertyAsString("ZD_DOMAIN_NAME"));
    return urlBuilder;
  }

  private void checkResponse(ClientResponse clientResponse)
    throws ApiException
  {
    String methodName = "checkResponse";
    print(methodName + String.format(" Invoked connection URL %s", clientResponse));
    int statusCode = clientResponse.getStatusInfo().getStatusCode();
    if (statusCode == 401)
    {
      throw new ApiException("Invalid credentials.", "");
    }
    if (!(clientResponse.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL))
    {
      throw new ApiException(clientResponse.getEntity(String.class), clientResponse.getStatusInfo().getReasonPhrase());
    }
  }

  private String getZendeskDomain()
  {
    return getZendeskURLBuilder().toString();
  }

  private String getUserName()
  {
    String userName = getPropertyAsString("ZD_USER_NAME");
    print("userName=" + userName);
    return userName;
  }

  private void print(String pMessage)
  {
    mLogger.logp(Level.INFO, mLogger.getName(), "print", pMessage);
  }

  private String getPassword()
  {
    return getPropertyAsString("ZD_PASSWORD");
  }

  private String getPropertyAsString(String pKey)
  {
    return (String) getProperties().get(pKey);
  }

  private Client getRestClient()
    throws ApiException
  {
    if (mRestClient == null)
    {
      mRestClient = Client.create();
      mRestClient.addFilter(new LoggingFilter(System.out));
      mRestClient.setReadTimeout(20000);
      mRestClient.setConnectTimeout(10000);
    }
    return mRestClient;
  }

  public WebResource getWebResource(String resource)
    throws ApiException
  {
    if (resource != null && !resource.isEmpty() && !resource.startsWith("/"))
    {
      resource += "/" + resource;
    }
    WebResource webResource = null;
    try
    {
      webResource = getRestClient().resource(getZendeskDomain()).path(resource);
    }
    catch (Exception e)
    {
      throw new ApiException(e.getMessage(), e.getMessage());
    }

    return webResource;
  } 
}
  • In order to compile your java class, you will need FlexDeployAPI.jar on classpath.
  • Implement all the methods described in the table in the API Implementation section.
  • For any failure connecting to the system or if any issues with the data, then you can throw exception. For example throw new ApiException("Invalid credentials.", "");
  • Once you are ready with unit testing, you can prepare Jar file for your credential store java class and other utility classes. This jar file can be placed on server classpath now.
    • For Tomcat, put this jar file in apache-tomcat-flexdeploy/lib folder.
    • For WebLogic, put this jar file in Domain lib folder.
    • If you are using any third party libraries from your Java implementation, then those jar files will also need to be added to same lib folder. Keep in mind that this can cause issues with server functioning, so be prepared to remove your additional library files.

Groovy Implementation

Here are high level steps for Groovy implementation. You can use any IDE to prepare this implementation. 

As groovy is able to access FlexDeploy variables and Java classes, you can take advantage of Java libraries from Groovy script. For example, if there is Java library used to access the change management system, you can places those in lib folder and use those classes from Groovy script. This allows you to keep dynamic part of implementation in Groovy and use Java library.

  • Create a groovy class. Example shown below has the methods implemented.
  • We are using BMC Helix Remedy Force as a usecase
  • All properties defined are available as groovy binding variables. For example, properties can be accessed directly like BMC_DOMAIN_NAME, BMC_SALESFORCE_HOST_NAME or BMC_USER_NAME etc
Example groovy BMCRemedyChangeManagementSystem.groovy
import flexagon.fd.model.integration.cms.api.ChangeManagementSystem;
import flexagon.fd.model.integration.cms.api.Request;
import flexagon.fd.model.integration.util.ApiException;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.filter.LoggingFilter
import com.sun.jersey.api.representation.Form;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;
import groovy.json.JsonOutput;
import flexagon.fd.model.integration.cms.impl.RequestImpl

class BMCRemedyChangeManagementSystem {
    def className = BMCRemedyChangeManagementSystem.class.getName();
    def jsonSlurper = new groovy.json.JsonSlurper()
    def accessToken = ""

    def createClient() {
        Client restClient = Client.create();
        restClient.addFilter(new LoggingFilter(System.out));
        restClient.setReadTimeout(20000);
        restClient.setConnectTimeout(10000);
        return restClient;
    }

    private void checkResponse(ClientResponse clientResponse)
    throws ApiException
    {
        String methodName = "checkResponse";
        log.logInfo(methodName, String.format(" Invoked connection URL %s", clientResponse));
        int statusCode = clientResponse.getStatusInfo().getStatusCode();
        if (statusCode == 401) {
            throw new ApiException("Invalid credentials.", "");
        }
        if (!(clientResponse.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL)) {
            throw new ApiException(clientResponse.getEntity(String.class), clientResponse.getStatusInfo().getReasonPhrase());
        }
    }

    def createRequest(String pDescription, String pComment)
    {
        String methodName = "createRequest()";
        log.logFinestEntering(methodName, pDescription, pComment);
        Request request = null;
        try {
            getAccessToken()
            Client mRestClient = createClient()
            String changeRequestURI = BMC_REMEDY_OBJECT_NAME_URI.replaceAll("\\{OBJECT_NAME\\}", "BMCServiceDesk__Change_Request__c")
            def jsonLiteral = ["BMCServiceDesk__Change_Description__c": "${pDescription}", "BMCServiceDesk__Reason_for_Change_Details__c" : "${pComment}"]
            ClientResponse clientResponse = mRestClient.resource(BMC_DOMAIN_NAME).path(changeRequestURI).accept(MediaType.APPLICATION_JSON_TYPE)
                .type(MediaType.APPLICATION_JSON_TYPE).header("Authorization", "Bearer " + accessToken)
                .post(ClientResponse.class, JsonOutput.toJson(jsonLiteral));
            checkResponse(clientResponse)
            String responseString = clientResponse.getEntity(String.class);
            log.logInfo(methodName, "response from CR creation =" + responseString);
            def jsonSlurper = new groovy.json.JsonSlurper()
            def response = jsonSlurper.parseText(responseString)
            log.logInfo(methodName, "created change request unique id=" + response.id);
            clientResponse = mRestClient.resource(BMC_DOMAIN_NAME).path(changeRequestURI + "/" + response.id)
                .type(MediaType.APPLICATION_JSON_TYPE).header("Authorization", "Bearer " + accessToken)
                .get(ClientResponse.class);
            responseString = clientResponse.getEntity(String.class);
            response = jsonSlurper.parseText(responseString)
            log.logInfo(methodName, "change request=" + response);
            request = createRequestForChange(response);
        }
        catch (Exception e)
        {
            log.logInfo(methodName, " Change Request creation failed " + e.getMessage() + " " + e)
            throw new ApiException("Change Request creation failed. " + e.getMessage());
        }
        log.logFinestExiting(methodName, request);
        return request;
    }

    def createRequestForChange(response)
    {
        Request request =
            new RequestImpl(response.Name, response.BMCServiceDesk__Change_Description__c, response.BMCServiceDesk__Status__c, ChangeManagementSystem.RequestType.REQUEST, null, "" + response.BMCServiceDesk__Approved__c,
                (!"Rejected".equalsIgnoreCase(response.BMCServiceDesk__ClosureCategory__c) && !response.BMCServiceDesk__Inactive__c), null);
        return request
    }

    def createIncident(String pDescription, String pComment)
    {
        String methodName = "createIncident()";
        log.logFinestEntering(methodName, pDescription, pComment);
        Request request = null;
        try {
            getAccessToken()
            Client mRestClient = createClient()

            String incidentURI = BMC_REMEDY_OBJECT_NAME_URI.replaceAll("\\{OBJECT_NAME\\}", "BMCServiceDesk__Incident__c")
            def jsonLiteral = ["BMCServiceDesk__shortDescription__c": "${pDescription}", "BMCServiceDesk__FKCategory__c": "a216g0000005NvDAAU", "BMCServiceDesk__incidentDescription__c": "${pComment}"]
            ClientResponse clientResponse = mRestClient.resource(BMC_DOMAIN_NAME).path(incidentURI).accept(MediaType.APPLICATION_JSON_TYPE)
                .type(MediaType.APPLICATION_JSON_TYPE).header("Authorization", "Bearer " + accessToken)
                .post(ClientResponse.class, JsonOutput.toJson(jsonLiteral));
            checkResponse(clientResponse)
            String responseString = clientResponse.getEntity(String.class);
            log.logInfo(methodName, "response from incident creation =" + responseString);
            def jsonSlurper = new groovy.json.JsonSlurper()
            def response = jsonSlurper.parseText(responseString)
            log.logInfo(methodName, "created incident unique id=" + response.id);
            clientResponse = mRestClient.resource(BMC_DOMAIN_NAME).path(incidentURI + "/" + response.id)
                .type(MediaType.APPLICATION_JSON_TYPE).header("Authorization", "Bearer " + accessToken)
                .get(ClientResponse.class);
            responseString = clientResponse.getEntity(String.class);
            response = jsonSlurper.parseText(responseString)
            log.logInfo(methodName, "incident details=" + response);
            request = createRequestForIncident(response);
        }
        catch (Exception e)
        {
            log.logInfo(methodName, "Incident creation failed " + e.getMessage() + " " + e)
            throw new ApiException("Incident creation failed. " + e.getMessage());
        }
        log.logFinestExiting(methodName, request);
        return request;
    }

    def createRequestForIncident(response)
    {
        Request request =
            new RequestImpl(response.Name, response.BMCServiceDesk__incidentDescription__c, response.BMCServiceDesk__Status__c, ChangeManagementSystem.RequestType.INCIDENT, null, "" + response.BMCServiceDesk__Approved__c,
                true, null);
        return request
    }

    def findRequestByType(String pRequestNumber, ChangeManagementSystem.RequestType pRequestType)
    {
        String methodName = "findRequest()";
        log.logFinestEntering(methodName, pRequestNumber);
        Request request = null;
        try {
            getAccessToken()
            Client mRestClient = createClient()
            String incidentURI = BMC_REMEDY_OBJECT_NAME_URI.replaceAll("\\{OBJECT_NAME\\}", "BMCServiceDesk__Change_Request__c")
            incidentURI += "/Name/" + pRequestNumber
            ClientResponse clientResponse = mRestClient.resource(BMC_DOMAIN_NAME).path(incidentURI).accept(MediaType.APPLICATION_JSON_TYPE)
                .header("Authorization", "Bearer " + this.accessToken)
                .get(ClientResponse.class);
            checkResponse(clientResponse)
            def jsonSlurper = new groovy.json.JsonSlurper()
            def response = jsonSlurper.parseText(clientResponse.getEntity(String.class))
            log.logInfo(methodName, " change request=" + response);
            request = createRequestForChange(response);
        }
        catch (Exception e)
        {
            log.logInfo(methodName, "Get request failed - " + e.getMessage() + " " + e)
            throw new ApiException("Get request failed. " + e.getMessage());
        }
        log.logFinestExiting(methodName, request);
        return request;
    }

    def isRequestApproved(String pRequestNumber, String pEnvironmentCode)
    {
        String methodName = "isRequestApproved()";
        log.logFinestEntering(methodName, pRequestNumber, pEnvironmentCode);
        Boolean approved = false;
        getAccessToken()
        RequestImpl request = findRequestByType(pRequestNumber, ChangeManagementSystem.RequestType.REQUEST);
        if (request != null) {
            if (request.getApproval() != null && request.getApproval().trim().length() > 0 && Boolean.valueOf(request.getApproval()) && request.isActive()) {
                approved = true;
            }
        }
        log.logFinestExiting(methodName, approved);
        return approved;
    }

    def isRequestRejected(String pRequestNumber, String pEnvironmentCode)
    {
        String methodName = "isRequestRejected()";
        log.logFinestEntering(methodName, pRequestNumber, pEnvironmentCode);
        Boolean rejected = false;
        getAccessToken()
        RequestImpl request = findRequestByType(pRequestNumber, ChangeManagementSystem.RequestType.REQUEST);
        if (request != null) {
            if (request.getApproval() != null && request.getApproval().trim().length() > 0 && ((!"OPENED".equalsIgnoreCase(request.getStatus()) && !Boolean.valueOf(request.getApproval())) || !request.isActive())) {
                rejected = true;
            }
        }
        log.logFinestExiting(methodName, rejected);
        return rejected;
    }

    def isDoPolling()
    {
        String methodName = "isDoPolling()";
        log.logFinestEntering(methodName);
        return false;
        log.logFinestExiting(methodName);
    }

    def getAccessToken()
    {
        String methodName = "getAccessToken()";
        log.logFinestEntering(methodName);
        try {
            if (accessToken == null || accessToken.trim().length() == 0) {
                Client mRestClient = createClient()
                log.logInfo(methodName, "BMC_USER_NAME=$BMC_USER_NAME, BMC_PASSWORD=$BMC_PASSWORD")

                Form form = new Form();
                form.add("grant_type", "password");
                form.add("client_id", BMC_CLIENT_ID)
                form.add("client_secret", BMC_CLIENT_SECRET)
                form.add("username", BMC_USER_NAME)
                form.add("password", BMC_PASSWORD)

                ClientResponse clientResponse = mRestClient.resource(BMC_SALESFORCE_HOST_NAME).path(BMC_SALESFORCE_OAUTH2_URI)
                    .type(MediaType.APPLICATION_FORM_URLENCODED_TYPE)
                    .accept(MediaType.APPLICATION_JSON_TYPE)
                    .post(ClientResponse.class, form);
                checkResponse(clientResponse)
                String responseString = clientResponse.getEntity(String.class);
                log.logInfo(methodName, "responseString=" + responseString);
                def response = jsonSlurper.parseText(responseString)
                accessToken = response.access_token
                String instanceUrl = response.instance_url
                if (!instanceUrl.equals(BMC_DOMAIN_NAME)) {
                    String message = "Instance URL from OAuth2 is different from what is configured in FlexDeploy, URL[${BMC_DOMAIN_NAME}] is changed to [${instanceUrl}]"
                    log.logInfo(methodName, message);
                    BMC_DOMAIN_NAME = instanceUrl
                }
                if (accessToken == null || accessToken.trim().length() == 0) {
                    throw new ApiException("Couldn't get acess token from BMC. Please check the  properties in the CMS config");
                }
                log.logInfo(methodName, "Access Token=" + accessToken + ",instanceUrl=" + instanceUrl);
            }
            log.logFinestExiting(methodName);
        }
        catch (Exception e)
        {
            log.logInfo(methodName, "Not able to get access token failed " + e.getMessage() + " " + e)
            throw new ApiException("Not able to get access token failed. " + e.getMessage());
        }
    }

    def checkConnection()
    {
        String methodName = "checkConnection()";
        log.logFinestEntering(methodName);
        try {
            getAccessToken()
            Client mRestClient = createClient()
            ///services/data/v33.0/sobjects/User
            String aboutMeURI = BMC_REMEDY_OBJECT_NAME_URI.replaceAll("\\{OBJECT_NAME\\}", "User")
            ClientResponse clientResponse = mRestClient.resource(BMC_DOMAIN_NAME).path(aboutMeURI)
                .type(MediaType.APPLICATION_JSON_TYPE).header("Authorization", "Bearer " + accessToken)
                .get(ClientResponse.class);
            checkResponse(clientResponse)

            def jsonSlurper = new groovy.json.JsonSlurper()
            def response = jsonSlurper.parseText(clientResponse.getEntity(String.class))
            log.logInfo(methodName, "Response from aboutMeURI =" + response);
        }
        catch (Exception e)
        {
            log.logInfo(methodName, " Test connection failed " + e.getMessage() + " " + e)
            throw new ApiException("Connection failed. " + e.getMessage());
        }
        log.logFinestExiting(methodName);
    }
}
  • Implement all the methods described in the table in the API Implementation section
  • For any failure connecting to the system or if any issues with the data, then you can throw exception. For example throw new ApiException("Invalid credentials.", "");

Groovy Utilities

There are some utility variables provided by FlexDeploy that can used in your custom Groovy code.

  • log is a FlexDeploy logger variable which should be used to log any information from the groovy class.
  • fdrestutils is a utility object available to use FlexDeploy API to invoke any REST API.
    • testConnection(String pHostName, String pUrl, String pUserName, String pPassword)
    • getRequest(String pHostName, String pResourcePath, String pUserName, String pPassword) - Returns javax.json.JsonObject
    • postRequest(String pHostName, String pUserName, String pPassword, String pResourcePath, String pResourceName, String pPayload) - Returns boolean
    • putRequest(String pHostName, String pUserName, String pPassword, String pResourcePath, String pPayload) - Returns boolean

      def builder = new groovy.json.JsonBuilder()
      def root = builder.issue
      {
          notes "${pComment}"
      }
      String payload = builder.toString();
      String ticketNumber = ticket.getNumber();
      String resourcePath = REDMINE_TICKET_REST_PATTERN.replaceAll("\\{REDMINE_ISSUE\\}", ticketNumber)
      fdrestutils.putRequest(REDMINE_URL, REDMINE_USER_NMAE, REDMINE_PASSWORD, resourcePath, payload);
The following macros are not currently supported in the footer:
  • style