July 31, 2012

Integrating Maximo with Java application through RMI

This entry is part of the Maximo Java Development series.

In this article I will describe how to call Maximo business objects methods remotely using a Java RMI connection. This technique can be useful to integrate Maximo in custom applications written in Java or to perform a particular processing of data stored in Maximo database using an external application.
For simplicity I will describe how to create a sample Java project using Eclipse to print the list of assets. However, this technique can be used in any Java application.
First of all you have to copy some jar files from the Maximo server to your development system. Go in the application deployment directory (e.g. WebSphere\AppServer\profiles\ctgAppSrv01\installedApps\ctgCell01\MAXIMO.ear) and copy the businessobjects.jar file and the entire lib directory.
Launch Eclipse, create an empty Java project and add the businessobject.jar and icu4j.jar files to the project classpath. Your project should look like this.


Now create an empty class named com.maximodev.MxRemoteConnection and paste the following code into it.

package com.maximodev;

import psdi.mbo.MboRemote;
import psdi.mbo.MboSetRemote;
import psdi.util.MXSession;

public class MxRemoteConnection
{
 
  /**
  * Sample main method to connect to Maximo server and list all the assets
  */
  public static void main(String[] args) throws Exception
  {
    MXSession session = getConnection("192.168.18.128", 13400, "MXServer", "maxadmin", "maxadmin");

    MboSetRemote assetMboSet = session.getMboSet("ASSET");
    assetMboSet.setOrderBy("ASSETNUM");
 
    MboRemote assetMbo;
    for(int j=0; ((assetMbo = assetMboSet.getMbo(j)) != null); j++)
    {
      String assetNum = assetMbo.getString("ASSETNUM");
      String location = assetMbo.getString("LOCATION");
      String desc = assetMbo.getString("DESCRIPTION");
      System.out.println(assetNum + " - " + location + " - " + desc);
    }    
  }

  private static MXSession getConnection(String host, int rmiPort, String serverName, String user, String pwd)
  {
    MXSession session = MXSession.getSession();

    String connHost = host + ":" + rmiPort + "/" + serverName;
    System.out.println("Connecting to " + connHost);

    session.setHost(connHost);
    session.setUserName(user);
    session.setPassword(pwd);

    try
    {
      session.connect();
    }
    catch (Exception e)
    {
      e.printStackTrace();
      return null;
    }
    System.out.println("Connection OK");

    return session;
  }
}

Update the parameters passed to the getConnection method in the first line of the main method according to your environment.
  • host: Hostname of the Maximo server
  • rmiPort: The RMI port of the Maximo application server. The default value is 13400. To find it, open the Maximo logs and search for a row like this - BMXAA6461I - Bound rmi://thehost:13400/MXServer
  • serverName: Name of the Maximo application server. The default value is MXServer.
  • user: Username used to connect.
  • pwd: Password used to connect.

Now run the Java application and it will (hopefully) connect to you Maximo/TPAE server and list all your assets. If you are having problems finding the correct settings, you may try to test RMI connection using the checkmxserver utility in [SMPDIR]\maximo\tools\maximo\internal directory.

Apart from the getConnection method the previous code snippet is very similar to any Maximo MBO Java code. The only relevant difference is in the following line of code.

MboSetRemote assetMboSet = session.getMboSet("ASSET");

This means you have to use the MXSession object to retrieve the first MboSet. After that you can use the same identical APIs used in standard MBO development.

28 comments:

  1. Jaime Alejandro VelezAugust 6, 2012 at 5:49 PM

    How i connect application through RMI if websphere or weblogic has Security Integrated?

    ReplyDelete
    Replies
    1. What do you mean with "Security Integrated"?
      I have a WebSphere server with the following configuration and I connect successfully:
      Security - Global Security
      - Enable administrative security: true
      - Enable application security: true

      Delete
    2. yes, for example the application server has LDAP Actived, this required security integrated actived, i had problems in the connection with Maximo from an extern application.

      Delete
  2. If LDAP enabled, how to connect Maximo through RMI. The below code tried ,but it is not working.. Could u plz help me..

    SecurityServiceRemote ss = null;
    session = (MXServerRemote) Naming.lookup("rmi://" + host);
    ss = (SecurityServiceRemote) session.lookup("SECURITY");
    sysInfo =ss.getSystemUserInfo();
    Above piece of code is being used for getting the connection in Maximo 6.2.7, but in maximo 7.5 what is the way to get the connection. How to retrieve the value for getSystemUserInfo().

    ReplyDelete
    Replies
    1. Your approach is different from mine.
      I have tested my code on a MAM 7.1 with LDAP enabled and it works.

      Delete
    2. Thanks for the confirmation..

      Delete
    3. Did you manage to get mbos witch maximo 7.5 and LDAP enabled?
      When I try to connect Im getting error

      psdi.util.MXAccessException: access#mxauthenabled

      Delete
    4. Bruno, Paul have you been able to find a way to connect to an LDAP enabled MAM 7.1? It is giving me that same access#mxauthenabled error

      Delete
    5. the same situation (psdi.util.MXAccessException: access#mxauthenabled)

      Delete
  3. how could i get java.sql.Connection object from MXSession, have you ever tried this thing.

    ReplyDelete
  4. Bruno, I'm getting the following error:

    java.security.AccessControlException: access denied ("java.net.SocketPermission" "pedror" "resolve")

    I`ve set a permission through rmi as follows and tried to invoke a policy file via arguments, but with no success :

    if (System.getSecurityManager() == null) {
    System.setSecurityManager(new RMISecurityManager());
    }

    Any hint?

    ReplyDelete
  5. Hi Bruno - Thanks for this article. Got a question.
    I have a User ID (ROSHANT) that belongs to a group that does not have access to the wotrack application.
    Using Java RMI I am able to access the workorder object and fetch a workorder number using this user ID. I would think Maximo should prevent access to the object ifthe user iD does not have access to the app?
    also Is there a way to implement security to prevent access to prohibited app objects ?

    ReplyDelete
    Replies
    1. Using RMI you are interacting with an application layer under the Maximo applications. That's why you application security are not checked.
      You should use Data Restrictions to ensure the rigth object restrictions.

      Delete
  6. Looks like parameters are swapped in the call and method prototype for getConnection() in the sample above, server name should go third

    ReplyDelete
    Replies
    1. You are right.
      I have fixed the sample code.
      Thanks

      Delete
  7. Bruno,
    We are having issues going through a firewall using NAT'D IP addresses. This sample Java works on either side to a local environment. But when we try to cross the firewall we get this error:

    Connecting to NAT’D IP:13400/MXServer

    psdi.util.MXSystemException: system#notboundexception

          at psdi.util.RMISession.connect(RMISession.java:113)

          at com.maximodev.DB2RemoteConnection.getConnection(DB2RemoteConnection.java:36)

          at com.maximodev.DB2RemoteConnection.main(DB2RemoteConnection.java:15)

    Caused by:java.rmi.ConnectException: Connection refused to host:localhost; nested exception is:

          java.net.ConnectException: Connection timed out: connect

          at sun.rmi.transport.tcp.TCPEndpoint.newSocket(Unknown Source)

          at sun.rmi.transport.tcp.TCPChannel.createConnection(Unknown Source)

    Any suggestions? ?

    ReplyDelete
  8. Bruno -

    RMI is throwing this error MX7506 with LDAP. Appreciate your help -

    Connecting to MXPC:13401/MXDEV
    psdi.util.MXAccessException: access#mxauthenabled
    at psdi.security.SecurityService.authenticateUser(SecurityService.java:347)
    at psdi.security.SecurityService.authenticateUser(SecurityService.java:281)
    at psdi.security.SecurityService.authenticateUser(SecurityService.java:268)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
    at java.lang.reflect.Method.invoke(Method.java:611)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:320)
    at sun.rmi.transport.Transport$1.run(Transport.java:171)
    at java.security.AccessController.doPrivileged(AccessController.java:362)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:167)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:547)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:802)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:661)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:906)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:929)
    at java.lang.Thread.run(Thread.java:761)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:255)
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:233)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:142)
    at psdi.security.SecurityService_Stub.authenticateUser(SecurityService_Stub.java:123)
    at psdi.util.RMISession.authenticateUser(RMISession.java:291)
    at psdi.util.RMISession.loadUserInfo(RMISession.java:172)
    at psdi.util.RMISession.connect(RMISession.java:57)
    at RMITEST4.getConnection(RMITEST4.java:37)
    at RMITEST4.main(RMITEST4.java:13)
    Exception in thread "main" java.lang.NullPointerException
    at RMITEST4.main(RMITEST4.java:16)

    Process completed.

    ReplyDelete
    Replies
    1. Do you have application security enabled?
      RMI is a mess when dealing with LDAP authentication.
      I have never managed to make it work,

      Delete
    2. Yes I have LDAP / WebSphere / Maximo - MS Active Directory LDAP enabled - has any one got RMI in this situation to work to your knowledge ?

      many thanks

      Delete
    3. We have it working but it requires to use IBM JDK and write a callback handler. Since our integration is from another web application, this introduces a lot of challenges as it has to be deployed on Websphere just like Maximo. We are looking for a better solution and I saw that one product out there, DataSplice, deploys a web page into Maximo which returns some kind of Authentication Token and this is used to connect to RMI Server and use MBO. Anyone know how this can be done?

      Here is the link at Datasplice where they mention it.

      http://wiki.datasplice.com/wiki/index.php/DataSplice_4.0/Administration_Guide/Additional_Information/Maximo_Application_Server_Authentication

      Delete
  9. hi Bruno ; I get the error in maximo 7.6

    psdi.util.MXSystemException: system#notboundexception
    psdi.util.MXSystemException: system#notboundexception
    at psdi.util.RMISession.connect(RMISession.java:106)
    at location.giris(location.java:33)
    at location.main(location.java:99)
    Caused by: java.rmi.NotBoundException: MXServer
    at sun.rmi.registry.RegistryImpl.lookup(RegistryImpl.java:148)
    at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
    at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:426)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:284)
    at sun.rmi.transport.Transport$1.run(Transport.java:189)
    at sun.rmi.transport.Transport$1.run(Transport.java:186)
    at java.security.AccessController.doPrivileged(AccessController.java:366)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:185)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:823)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1176)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:853)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source)
    at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)
    at sun.rmi.server.UnicastRef.invoke(Unknown Source)
    at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
    at java.rmi.Naming.lookup(Unknown Source)
    at psdi.util.RMISession.getMXServer(RMISession.java:280)
    at psdi.util.RMISession.connect(RMISession.java:60)
    ... 2 more

    ReplyDelete
    Replies
    1. I got same problem on 7.6.
      same program code on 7.5 is ok.
      did you fix?

      Delete
    2. fixed.
      find out reason is setup not yet completed.

      Delete
    3. Can you please provide what you did to fix this issue? We have this issue on 7.6.02 still.

      Delete
  10. Hi , Does Bean class/Field Level class follow RMIC methodology?Why in Maximo we wont do RMIC compilation for Bean class/Field Level classes?

    ReplyDelete
  11. Anyone managed to get this LDAP connection to work? I am facing the same issue psdi.util.MXAccessException: access#mxauthenabled

    ReplyDelete