Pages

August 30, 2018

Sending SMS from Maximo calling an external Web service

In my last project I had to implement a customization to send SMS messages using Skebby. The service APIs are obviously based on REST and JSON so I ended up writing an automation script to integrate Maximo with the Skebby service.
In the process of writing the code I have faced (and solved) some interesting issues so the developed script is quite complex and is an interesting demonstration of several useful techniques:
  1. External REST service invocation (POST and GET)
  2. JSON manipulation
  3. Retrieve Maximo system properties
  4. Usage of Java classes
  5. Appropriate logging using MXLoggerFactory
  6. Display error messages with parameters
The script is based on WORKORDER object and requires two custom system properties (sms.username, sms.password) and two messages (SmsSendError, SmsSendOk).
Here it is.
from java.lang import String
from java.io import BufferedReader, InputStreamReader
from java.net import URL, URLEncoder
from java.nio.charset import StandardCharsets
from com.ibm.json.java import JSONObject, JSONArray

from psdi.server import MXServer
from psdi.util.logging import MXLoggerFactory

logger = MXLoggerFactory.getLogger("maximo.script")
logger.debug("Entering SEND_SMS script")


BASEURL = "https://api.skebby.it/API/v1.0/REST/"
SMS_SENDER = "Maximo"
SMS_DEST = "+3933511111111"

sms_text = "Ticket " + mbo.getString("WONUM") + " - " + mbo.getString("DESCRIPTION")

properties = MXServer.getMXServer().getConfig()
username = properties.getProperty("sms.username")
password = properties.getProperty("sms.password")

urltxt = BASEURL + "login?username=" + URLEncoder.encode(username, "UTF-8") + "&password=" + URLEncoder.encode(password, "UTF-8")
logger.debug("Authenticating: " + urltxt)
url = URL(urltxt)
conn = url.openConnection()
conn.setRequestMethod("GET")

if conn.getResponseCode() != 200:
  conn.disconnect()
  msg = "HTTP Error: " + str(conn.getResponseCode()) + " - " + str(conn.getResponseMessage())
  logger.error(msg)
  service.error("asts", "SmsSendError", [str(conn.getResponseCode()), str(conn.getResponseMessage()), "Authentication failed"])

br = BufferedReader(InputStreamReader(conn.getInputStream()))
authResp = br.readLine()
conn.disconnect()

#logger.debug("Authentication output:" + authResp)
# auth tokens are returned separated by a ';' character
user_key,session_key = authResp.split(';')

logger.debug("Authentication tokens:" + user_key + "," + session_key)

logger.info("Sending SMS to " + SMS_DEST + " - " + sms_text)

url = URL(BASEURL + "sms")
conn = url.openConnection()
conn.setRequestMethod("POST")
conn.setRequestProperty("user_key", user_key)
conn.setRequestProperty("Session_key", session_key)
conn.setRequestProperty("content-type", "application/json")
conn.setDoOutput(True)

recipients = JSONArray()
recipients.add(SMS_DEST)

obj = JSONObject()
obj.put("message_type", "TI")
obj.put("returnCredits", False)
obj.put("sender", SMS_SENDER)
obj.put("recipient", recipients)
obj.put("message", sms_text)
jsonStr = obj.serialize(False)

logger.debug("SMS Json Request=" + jsonStr)

os = conn.getOutputStream()
postData = String.getBytes(jsonStr, StandardCharsets.UTF_8)
os.write(postData)
os.flush()

if conn.getResponseCode() != 201:
  br = BufferedReader(InputStreamReader(conn.getErrorStream()))
  output = br.readLine()
  logger.error("Error: " + output)
  conn.disconnect()
  msg = "HTTP Error: " + str(conn.getResponseCode()) + " - " + str(conn.getResponseMessage() + " - " + output)
  logger.error(msg)
  service.error("asts", "SmsSendError", [str(conn.getResponseCode()), str(conn.getResponseMessage()), output])

br = BufferedReader(InputStreamReader(conn.getInputStream()))
output = br.readLine()
logger.info("OK: " + output)
conn.disconnect()

service.setWarning("asts", "SmsSendOk", None)


The script has been developed to avoid external dependencies like this example.

7 comments:

  1. You are alive! I'm so glad you are still posting articles. We've missed you!

    ReplyDelete
  2. Hello, Bruno. I love your work. I tried to implement your script for testing purposes on Maximo 7.6.0.9 and Maximo 7.6.1, but on both systems I get Certificate error, saying:
    BMXAA7837E - An error occured that prevented the {0} script for the {1} launch point from running
    javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLHandshakeException: com.ibm.jsse2.util.h: PKIX path building failed: java.security.cert.CertPathBuilderException: PKIXCertPathBuilderImpl could not build a valid CertPath.; internal cause is:
    java.security.cert.CertPathValidatorException: The certificate issued by CN=DigiCert Global Root CA, OU=www.digicert.com, O=DigiCert Inc, C=US is not trusted; internal cause is:
    java.security.cert.CertPathValidatorException: Certificate chaining error in script at line number 30

    Please can you tell me if you also run into this probblem?

    ReplyDelete
    Replies
    1. Ok. I imported the DigiCert Global Root CA into WebSphere and I've got a little further. Now I get this Error:
      BMXAA7837E - An error occured that prevented the {0} script for the {1} launch point from running
      javax.net.ssl.SSLException: javax.net.ssl.SSLException: java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 64 in script at line number 30

      Any idea?

      Delete
    2. OK.
      I set handshaking from SSL_TLS to SSL_TLSv2 on WebSphere and now there is no error anymore.
      https://developer.ibm.com/answers/questions/209245/ssl-exception-error-in-wesphere-application-server/

      Delete
    3. Thank you for the updates.
      Useful for other people around here...

      Delete
  3. Make sure that your business plan is extraordinary and is able to get you the attention of potential customers. I am so happy that with the use of text messaging service for business I have been getting absolute results. Moreover, these are very affordable too.

    ReplyDelete
  4. Do you have an example to consume SOAP from an automation script?

    ReplyDelete

Note: Only a member of this blog may post a comment.