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:
- External REST service invocation (POST and GET)
- JSON manipulation
- Retrieve Maximo system properties
- Usage of Java classes
- Appropriate logging using MXLoggerFactory
- 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.
Sending SMS from Maximo calling an external Web service
You are alive! I'm so glad you are still posting articles. We've missed you!
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?
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?
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/
Thank you for the updates.
Useful for other people around here…
Thank you!
Do you have an example to consume SOAP from an automation script?
When I am trying to call .Net webserive from Maximo 7.6. i am getting below error.
psdi.util.MXSystemException: BMXAA1481E – Cannot deliver the message to the endpoint.
java.io.IOException: Async IO operation failed (3), reason: RC: 107 Transport endpoint is not connected
at psdi.iface.router.WebServiceHandler.invoke(WebServiceHandler.java:258)
at psdi.iface.mic.MicService.routeData(MicService.java:472)
at psdi.iface.app.endpoint.MaxEndPointTestSet.execute(MaxEndPointTestSet.java:131)
at psdi.webclient.beans.endpoint.EndPointTestBean.testxml(EndPointTestBean.java:59)
at sun.reflect.GeneratedMethodAccessor252.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
at java.lang.reflect.Method.invoke(Method.java:508)
It is throwing in Prod only but not in test environments. Any suggestions please????
Hi Bruno, Thanks alot for your useful ideas .
During trying this method an erroe message displayed to me
the error says:
java.net.SocketException: java.net.SocketException: Permission denied: connect in
Kindly your comment