IBM Support

Maximo Rest Client Example: Calling an External REST Service (Logo Tiger 3) with a Maximo Client

Technical Blog Post


Abstract

Maximo Rest Client Example: Calling an External REST Service (Logo Tiger 3) with a Maximo Client

Body

MOTIVATION:

When I searched for a REST client implemented within Maximo using Automation Scripting, all documents I could find gave information on Maximo REST services which is the reverse of my requirement. Hence, I thought it would be a good idea to post this example which can ease the things for developers looking for a similar requirement.

Maximo is focused on Asset Management, hence most of the time on customer site we need to integrate Maximo with ERP (SAP ERP, Oracle ERP etc.) or billing systems. I will present an example of a Maximo Jython REST client which sends information on company business object of Maximo to create a current (account) object on Logo Tiger (an ERP software from Turkey). Actually, I integrated company, item and purchase order objects for my project but I want to demostrate companies now since it is the simplest among all.

 

PREPARATION:

 

Maximo v7.6, which is the up-to-date version, supports Apache HttpClient 4.1 which will be used for our REST operations.

Note on Preliminary Work: Apache HttpComponents 4.5.3 is the latest version of http client and it includes more elegant and simple methods for development. First, I succesfully tested it via an external Java client but when I translated my code into Jython and ran it on Maximo I encountered “java.lang.NoClassDefFoundError”. This root cause of this error is that HttpComponents 4.5.3 library is surpassed by application server library (Websphere 8.5.5). I tried changing the order of class loaders and defining library within both Maximo and Websphere which did not work out. Then, I gave up on the latest version and used the version compatible with Maximo v7.6 and Websphere 8.5.5 which is Apache HttpClient 4.1.3.

 

You can download the client library and its dependencies from the links below:

httpclient-4.1.3.jar:

https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient/4.1.3

dependencies (httpcore-4.1.4.jar, commons-codec-1.4.jar, commons-logging-1.1.1.jar):

https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore/4.1.4

https://mvnrepository.com/artifact/commons-codec/commons-codec/1.4

https://mvnrepository.com/artifact/commons-logging/commons-logging/1.1.1

 

Since ext folder is in the classpath of application server, the most practical way is to copy these jars into the application server ext folder and restart Websphere.

 

The path for Websphere ext folder in Windows:

…\IBM\WebSphere\AppServer\lib\ext

 

DEVELOPMENT:

 

There is an online manual for Logo Tiger Objects REST Services, which can be accessed through the link below:

https://wikidocs.logo.com.tr/display/WUA/Logo+Objects+REST+Servis

 

According to the manual, we first need to get an access token via an http POST operation with basic authentication and some header parameters. Then, we will process another http POST with the response (access token) of first POST in the header authorization of type Bearer and the rest of the data as JSON body of the request.

 

First, we need to define a couple of parameters as Maximo system properties. They will be used for calling the REST service and getting access token.

image

 

 

 

 

 

 

 

 

 

 

 

 

 

Figure 1 - System Properties for REST Service

 

Then, we create an Automation Script with action type of launch point. It works on COMPANIES object. The Jython code for the Maximo REST Client is as follows:

  # LOGO REST Client - Maximo Company to Logo Tiger Current Account  from com.ibm.json.java import JSONObject    from java.io import BufferedReader, IOException, InputStreamReader  from java.lang import System, Class, String, StringBuffer  from java.nio.charset import Charset  from java.util import Date, Properties, List, ArrayList    from org.apache.commons.codec.binary import Base64  from org.apache.http import HttpEntity, HttpHeaders, HttpResponse, HttpVersion  from org.apache.http.client import ClientProtocolException, HttpClient  from org.apache.http.client.entity import UrlEncodedFormEntity  from org.apache.http.client.methods import HttpPost  from org.apache.http.entity import StringEntity  from org.apache.http.impl.client import DefaultHttpClient  from org.apache.http.message import BasicNameValuePair  from org.apache.http.params import BasicHttpParams, HttpParams, HttpProtocolParamBean    from psdi.mbo import Mbo, MboRemote, MboSet, MboSetRemote  from psdi.security import UserInfo  from psdi.server import MXServer    from sys import *    # method for getting the access token with basic authentication  def getAccessToken():      token = ""      # get connection properties from System Properties      properties = MXServer.getMXServer().getConfig()      host = properties.getProperty("logo.rest.host")      uri = host + '/api/v1/token'      clientid = properties.getProperty("logo.rest.clientid")      clientsecurity = properties.getProperty("logo.rest.clientsecurity")      username = properties.getProperty("logo.rest.username")      password = properties.getProperty("logo.rest.password")      firmno = properties.getProperty("logo.rest.firmno")      System.out.println('getAccessToken() - Properties fetched')        # get authentication header      auth = clientid + ":" + clientsecurity      encodedAuth = String(Base64.encodeBase64(String.getBytes(auth, 'ISO-8859-1')),"UTF-8")      authHeader = "Basic " + str(encodedAuth)        # get http parameters      params = BasicHttpParams()      paramsBean = HttpProtocolParamBean(params)      paramsBean.setVersion(HttpVersion.HTTP_1_1)      paramsBean.setContentCharset("UTF-8")      paramsBean.setUseExpectContinue(True)        # get http body entities      formparams = ArrayList()      formparams.add(BasicNameValuePair("grant_type", "password"))      formparams.add(BasicNameValuePair("username", username))      formparams.add(BasicNameValuePair("password", password))      formparams.add(BasicNameValuePair("firmno", firmno))      entity = UrlEncodedFormEntity(formparams, "UTF-8")        # get client, http headers and request      client = DefaultHttpClient()      request = HttpPost(uri)      request.setParams(params)      request.addHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded")      request.addHeader(HttpHeaders.ACCEPT, "application/x-www-form-urlencoded")      request.addHeader(HttpHeaders.AUTHORIZATION, authHeader)      request.setEntity(entity)        # get client response      response = client.execute(request)        # return JSON response and access token      status = response.getStatusLine().getStatusCode()      obj = JSONObject.parse(response.getEntity().getContent())      token = str(obj.get("access_token"))      return {'client':client, 'token':token}    # method for releasing the open client connection  def releaseConnection(client):      if(client != None):          client.getConnectionManager().shutdown()    # method for creating the JSON string which is sent in http POST body  def createJSONstring():      jsonStr = ""      currCode = {'TL': 0, 'USD': 1, 'EURO': 2}        currency = mbo.getString("CURRENCYCODE")      obj = JSONObject()      obj.put("INTERNAL_REFERENCE", 0)      obj.put("RECORD_STATUS", 0)      obj.put("CURRENCY", currCode[currency])      obj.put("ACCOUNT_TYPE", 3)      obj.put("CODE", mbo.getString("CODE"))      obj.put("TITLE", mbo.getString("NAME"))      obj.put("ADDRESS1", mbo.getString("ADDRESS1"))      obj.put("ADDRESS2", mbo.getString("ADDRESS1"))      obj.put("CITY", mbo.getString("ADDRESS3"))      obj.put("TOWN", mbo.getString("ADDRESS2"))      obj.put("POST_CODE", mbo.getString("ADDRESS4"))      obj.put("COUNTRY_CODE", mbo.getString("ADDRESS5"))      obj.put("TELEPHONE1", mbo.getString("PHONE"))      obj.put("TELEPHONE2", mbo.getString("CELLPHONE"))      obj.put("FAX", mbo.getString("FAX"))      obj.put("TAX_OFFICE", mbo.getString("TAXOFFICE"))      obj.put("TAX_ID", mbo.getString("REGISTRATION2"))      jsonStr = obj.serialize(True)      return jsonStr    # method for http POST using the path, JSON body and token with bearer authorization  def httpPost(path, jsonstring, token):      reference = None      # get connection properties from System Properties      properties = MXServer.getMXServer().getConfig()      host = properties.getProperty("logo.rest.host")      uri = host + path        # get authentication header      authHeader = "Bearer " + token        # get http parameters      params = BasicHttpParams()      paramsBean = HttpProtocolParamBean(params)      paramsBean.setVersion(HttpVersion.HTTP_1_1)      paramsBean.setContentCharset("UTF-8")      paramsBean.setUseExpectContinue(True)        # get http body entities      entity = StringEntity(jsonstring, "UTF-8")        # get client, http headers and request      client = DefaultHttpClient()      request = HttpPost(uri)      request.setParams(params)      request.addHeader(HttpHeaders.CONTENT_TYPE, "application/json")      request.addHeader(HttpHeaders.ACCEPT, "application/json")      request.addHeader(HttpHeaders.AUTHORIZATION, authHeader)      request.setEntity(entity)        # get client response      response = client.execute(request)        # return JSON response and reference number      status = response.getStatusLine().getStatusCode()      obj = JSONObject.parse(response.getEntity().getContent())      reference = int(obj.get("INTERNAL_REFERENCE")) if obj.get("INTERNAL_REFERENCE") != None else None      return reference    # method for creating Maximo company record as a current account in Logo   def addCompany2Logo():      jsonstr = createJSONstring()      client = None      try:          connection = getAccessToken()          client = connection['client']          token = connection['token']          System.out.println( 'TOKEN: ' + token)          reference = httpPost("/api/v1/Arps", jsonstr, token)          if(reference != None):              mbo.setValue("LOGOREFNO", reference, 11L)              mbo.getThisMboSet().save()              System.out.println( 'REFERENCE: ' + str(reference))      except:          System.out.println( 'Error:' + str(exc_info()[0]) + str(exc_info()[1]))      finally:          releaseConnection(client)          System.out.println( 'finally - all connections closed')    # Main part  addCompany2Logo()  

Code 1 - Jython Code for Rest Client

 

Finally, the action for the script above is substituted in an escalation which runs under a proper condition in an adequate time interval. One can alter this code to their specific needs for any other REST service or use it in a workflow or as an object event instead of an escalation.

 

[{"Business Unit":{"code":"BU059","label":"IBM Software w\/o TPS"},"Product":{"code":"SSLKT6","label":"IBM Maximo Asset Management"},"Component":"","Platform":[{"code":"PF025","label":"Platform Independent"}],"Version":"","Edition":"","Line of Business":{"code":"LOB59","label":"Sustainability Software"}}]

UID

ibm11129845