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

May 31, 2017 Yalcin Kumbasar

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.

 

Previous Article
How to Change layers visibility and their info display through Layers Tool
How to Change layers visibility and their info display through Layers Tool

Sometimes using Maximo Spatial, user will prefer to see only specific layers on the map in order to have a ...

Next Article
Fetching Daily Exchange Rates from xml feed provided by Turkish National Bank

I will present you a simple Jython script to fetch daily exchange rates using the xml feed provided by Turk...

×

Want our latest news? Subscribe to our blog!

Last Name
First Name
Thank you!
Error - something went wrong!