Skip to Content

Overview

Recently I started to wonder how to get message content and audit logs for message after processing in Adater Engine. If Message comes to PI, usually is processed in Abap stuck and there everything seems to be rather clear. We have some function modules like

SXMB_GET_MESSAGE_DATA

Or we can check main tables like

SXMSPMAST           XI Messages – Master

SXMSPVERS           Integration Engine: Message Version

SXMSCLUP  Cluster – Compressed Message Payload Property

As a last resort we can debug sxi_monitor transaction to receive message data, current status or payload. But how can we get those values from Java stuck. Of course we can read table data

XI_AF_MSG  AF XI              Message

XI_AF_MSG_AUDIT           Audit Log Entries

But it is not the solution and sometimes data aren’t kept in human readable format like payload is kept in blob format.

In PI 7.1 we have standard WebService like described in Michael’s blog. Disadvantage of this solution is that we do not receive Audit Log for processed message and this WebService in not available for  PI 7.0.

Purpose

Let suppose I would like to build some external tool to trace selected message’s flow. I will receive information about errors in Abap stuck through CCMS and in Java stuck with Alert mechanism. But it’s not enough for me. I would like to have full information about message and Audit Log in java based on message id.

Development

First approach – Java DB tables

Read Java tables – not acceptable

Second approach – Jar files

So I started to check what kind of possibilities I have. First of all I downloaded some jar files from PI server and checked what kind of class and methods they offer.

To receive information about Message I discovered in aii_af_ms_impl.jar file, class MessageStore and method getMemoryMessageBeans(MessageBeanFilter filter) where MessageBeanFilter is filter similar to this with we set in http://<server>:<port>/mdt/index.jsp .

In aii_af_svc.jar file I have class AuditLogManger. So at the beginning I started to use method getAuditEntryList(AuditMessageKey msgKey) but I receive error message. After struggling with AuditLogManager class I receive in my WebService correct result and the problem was with Connection class that provide access to Java Database. But this method seems to be very raw and unreliable but at least it was working. I started to search more and discovered some very nice Enterprise Java Beans offered by our J2EE server with is SAP Netweaver.

Third approach – Enterprise JavaBeans

In NWA i have list of all available modules and assigned to it Enterprise JavaBeans. I’m interested in module aii_af_ms_app_ejb.

AuditLog1.jpg

Inside this module i will find EJB with I’m particularly interested in and there name is messaging.system.MonitorBean and messaging.system.AuditLogBean

AuditLog2.jpg

Let’s now focus on MonitorBean with I will use to fetch message detail from PI. As each bean this one has JNDI used for search it in lookup and interface MonitorHI that allow WebService to obtain reference to specific bean.

AuditLog3.jpg

EJB functionality is accessed by means of remote interface, which define the business methods visible to, and called by WebService. MonitorRI interface contains lot of very use full methods and is implemented by MonitorBeanImpl. Some use full methods:

MessageBean getMessageBean(MessageKey paramMessageKey, int paramInt) – return message details for message key ( consists of message id and message direction)

byte[] getMessageBytes(MessageKey paramMessageKey, int paramInt) – return whole XI Message with payload.

MonitorBean getMonitorBean(MessageBeanFilter paramMessageBeanFilter) – return all messages that fulfil requirements set in MessageBeanFilter, that contains additional criteria for filter like interface name, sender service etc.

Similar for AuditLogBean I will use interface AuditLogBI and method

ArrayList getLogEntries(AuditMessageKey paramAuditMessageKey, int paramInt)

-return all AuditLogEntry for selected auditMessageKey( consist of message id and message key)

After download jar files that contains those class from J2EE server i can start building WebService. There are plenty of tutorials on SDN how to build java WebService from EJB.

Code

In my bean i had to add some references etc.

Method code to receive Message details

MonitorHI _mhi;

MonitorBI _monb;

try

{

      InitialContext ctx = new InitialContext();

      Object obj = ctx.lookup(“messaging.system.MonitorBean”);

      if( obj != null)

      {

            _mhi = (MonitorHI) obj;

            _monb= (MonitorBI) _mhi.create();

      }

}

catch(Exception ex)

{

}

Home interface MonitorHI can be used to execute method create()  and receive Remote interface MonitorRI. This interface type extends MonitorBI interface so we can cast it to MonitorBI or use MonitorRI

Next step it to call requested method like

MessageKey _mk = null;             

MessageDirection _mess_dir = null;                                     

_mess_dir = MessageDirection.INBOUND;

_mk = new MessageKey(“YOUR MESSAGE ID”,_mess_dir);

MessageBean _result = null;

try

{

_result = _monb.getMessageBean(_mk,i_cluster);

}

catch(Exception el)

{

}

Where _mk is MessageKey and i_cluster is int variable that contain node/cluster id and can be omitted with value 0.

Similar approach can be used to receive array of AuditLogEntry

Test

Log on to Wsnavigator and test WebServices

AuditLog4.jpg

GetMessage

AuditLog5.jpg

GetAuditLogs

AuditLog6.jpg


To report this post you need to login first.

16 Comments

You must be Logged on to comment or reply to a post.

    1. Iliya Kuznetsov

      I’ve failed with getting APIAccess class 🙁   But, at your possible UDF or Http Servlet you can bind to JNDI com.sap.engine.interfaces.messaging.api.public and you’ll get public interface PublicAPIAccess.

      (0) 
  1. Iliya Kuznetsov

    Just a note for success story 7.31. Two ways (at least) of using that code are possible.

    First way: UDF. It’s quite easy:

    1. Locate com.sap.aii.af.ms.ifc_api.jar and load it as imported archive IA_IFC.

    2. Create FL or MM

    3. Make dependencies as follow (beside default):

      a. To imported archive IA_IFC

      b. import javax.naming.*;

          import com.sap.engine.interfaces.messaging.api.*;

    4. Append simple function ApiAccessTest execution type SingleValues with the only parameter msgid

    5. The proof-of-concept code is follow:


    Object o;

      InitialContext ctx;

      APIAccess a;

      AbstractTrace tr = container.getTrace();

      try {

       ctx = new InitialContext();

       o = ctx.lookup(“com.sap.engine.interfaces.messaging.api”);

       if (o==null) throw new StreamTransformationException(“APIAccess isn’t got”);

       a = (APIAccess)o;

       tr.addInfo(“APIAccess got well: ” + a);

      } catch (NamingException e) {

       throw new StreamTransformationException(“Can’t detect JNDI. Error: ” + e.getExplanation());

      }

      return “” + msgid + “;test”;


    6. Check compilation and test mapping result. It’s the base for follow steps. Good luck!

    (0) 
    1. Michal Basl

      I have problem in “a = (APIAccess)o;” row.

      If I put to row before this code “trace.addInfo(obj.toString());” I received in trace this message: com.sap.engine.messaging.impl.api.APIAccessImpl@6255b154

      and than is exception raised:

      Exception:[java.lang.ClassCastException: class com.sap.engine.messaging.impl.api.APIAccessImpl:service:com.sap.aii.af.ms.svc@com.sap.engine.boot.loader.ResourceMultiParentClassLoader@2e3ed883@alive incompatible with interface com.sap.engine.interfaces.messaging.api.APIAccess:com.sap.aii.ibrep.server.mapping.rt.ArchiveClassLoader@15a8e5c4]

      Seems that I’m receiving little bit different type of object than I expect, right?

      I’m running and testing it in Builder, not running whole message including transformation.

      (0) 
    2. Michal Basl

      And I still don’t understand how can I find out old message through MessageID and check it’s status (successfully processed, failed in transformation, in channel etc.) from another transaction.

      Maybe I put here wrong comment without question…

      (0) 
      1. Iliya Kuznetsov

        JDBC_http://sap.com/xi/XI/System
        &lt;local&gt;

        null
        null
        6533
        XXX|XXXXX_D
        content-type=multipart/related; boundary=SAP_1c92b0e8-4567-11e4-afd4-000007a372ba_END; type=&quot;text/xml&quot;; start=&quot;&lt;soap-1c92b0e7456711e49591000007a372ba@sap.com&gt;&quot;
        http=POST
        content-length=6533

        S 2014-09-26 14:23:09 JDBC_SUC_004 CC_BankPair_JDBC_Send,null,null,null,null,
        S 2014-09-26 14:23:09 JDBC_SUC_005 CC_BankPair_JDBC_Send,1,null,null,null,
        S 2014-09-26 14:23:09 JDBC_SUC_009 3478,null,null,null,null,
        S 2014-09-26 14:23:09 MP: processing local module {0} localejbs/CallSapAdapter,null,null,null,null,
        S 2014-09-26 14:23:09 SEND_TRYING JDBC_http://sap.com/xi/XI/System,XI,null,null,null,
        S 2014-09-26 14:23:09 SEND_QUEUE_PUT_TRYING null,null,null,null,null,
        S 2014-09-26 14:23:09 QUEUE_PUT_SUCCESS null,null,null,null,null,
        S 2014-09-26 14:23:09 SEND_SUCCESS JDBC_http://sap.com/xi/XI/System,null,null,null,null,
        S 2014-09-26 14:23:09 SEND_QUEUE_GET_SUCCESS null,null,null,null,null,
        S 2014-09-26 14:23:09 STATUS_SET_SUCCESS DLNG,null,null,null,null,
        S 2014-09-26 14:23:09 SEND_QUEUE_PUT_TRYING null,null,null,null,null,
        S 2014-09-26 14:23:09 QUEUE_PUT_SUCCESS null,null,null,null,null,
        S 2014-09-26 14:23:09 SEND_QUEUE_GET_SUCCESS null,null,null,null,null,
        S 2014-09-26 14:23:09 STATUS_SET_SUCCESS DLNG,null,null,null,null,
        S 2014-09-26 14:23:09 SEND_QUEUE_PUT_TRYING null,null,null,null,null,
        S 2014-09-26 14:23:09 QUEUE_PUT_SUCCESS null,null,null,null,null,
        S 2014-09-26 14:23:09 SEND_QUEUE_GET_SUCCESS null,null,null,null,null,
        S 2014-09-26 14:23:09 STATUS_SET_SUCCESS DLNG,null,null,null,null,
        S 2014-09-26 14:23:09 AAE_REQUEST_MAPPING urn:mapping:001BankImport:SVNSI,BankPairNotification__BankProxyNotification,cbf5bad0b0be11e29710cb3b0a0000fe,null,null,
        S 2014-09-26 14:23:09 AFW_DELIVER CC_JPR_Recv,null,null,null,null,
        S 2014-09-26 14:23:09 MP: processing local module {0} localejbs/sap.com/com.sap.aii.af.soapadapter/XISOAPAdapterBean,null,null,null,null,
        S 2014-09-26 14:23:09 XI packaging (bulk mode) is not enabled. Switching to normal processing…. null,null,null,null,null,
        S 2014-09-26 14:23:09 XISOAP: XI message received for processing null,null,null,null,null,
        S 2014-09-26 14:23:09 SOAP: Request message entering the adapter processing with user j2ee_gst_jxd null,null,null,null,null,
        S 2014-09-26 14:23:09 REQUEST XI,http://localhost:51200/MessagingSystem/receive/JPR/XI,User,PIAPPLJXD2,null,
        S 2014-09-26 14:23:09 RECEIVE_QUEUE_PUT_TRYING JPR,null,null,null,null,
        S 2014-09-26 14:23:09 QUEUE_PUT_SUCCESS null,null,null,null,null,
        S 2014-09-26 14:23:09 RECEIVE_QUEUE_GET_SUCCESS null,null,null,null,null,
        S 2014-09-26 14:23:09 SOAP: Processing completed null,null,null,null,null,
        S 2014-09-26 14:23:09 STATUS_SET_SUCCESS DLNG,null,null,null,null,
        S 2014-09-26 14:23:09 SEND_TRANSMIT_SUCCESS JDBC_http://sap.com/xi/XI/System,<local&gt;,null,null,null,
        S 2014-09-26 14:23:09 JPR_IN_ACCEPTED null,null,null,null,null,
        S 2014-09-26 14:23:09 STATUS_SET_SUCCESS DLVD,null,null,null,null,
        S 2014-09-26 14:23:09 Calling Invoke Method null,null,null,null,null,
        S 2014-09-26 14:23:11 Back after executing Invoke Method null,null,null,null,null,
        S 2014-09-26 14:23:11 JPR_IN_PROCESS_SUCCESS null,null,null,null,null,
        S 2014-09-26 14:23:11 RECEIVE_DELIVER_SUCCESS JPR,null,null,null,null,
        S 2014-09-26 14:23:11 STATUS_SET_SUCCESS DLVD,null,null,null,null,

        (0) 
  2. Michal Basl

    Everything works fine in PI 7.3, but not in 7.11.

    Maybe it’s useful for many people who use 7.3 version, here is the result:

    1)

    pick-up library from PI system:

    /usr/sap/XYZ/DVEBMGS00/j2ee/cluster/bin/interfaces/com.sap.aii.af.ms.ifc/lib/com.sap.aii.af.ms.ifc_api.jar

    2)

    import it to PI as Imported Object

    /wp-content/uploads/2014/09/pic01_551608.jpg

    3)

    create new UDF

    3a)

    link imported jar at “Archives Used” tab

    /wp-content/uploads/2014/09/pic02_551621.jpg

    3b)

    import all needed classes in “Import Instructions” tab

    /wp-content/uploads/2014/09/pic03_551622.jpg

    3c)

    modify parameters and source of function

    /wp-content/uploads/2014/09/pic04_551623.jpg

    Object obj;

    String out = null;

    InitialContext initContext;

    APIAccess apiAccess = null;

    AbstractTrace trace = container.getTrace();

    try {

        initContext = new InitialContext();

        obj = initContext.lookup(“com.sap.engine.interfaces.messaging.api”);

        apiAccess = (APIAccess) obj;

    } catch (NamingException e) {

        trace.addWarning(“Can’t detect JNDI. Error: ” + e.getExplanation());

    }

    MessageAccess msgAccess = apiAccess.getMessageAccess();

    MessageDirection msgDirection = MessageDirection.valueOf(aDirection);

    MessageKey msgKey = new MessageKey(aMessageID, msgDirection);

    MessageData msgData = null;

    try {

        msgData = msgAccess.getMessageData(msgKey);

        out = msgData.getStatus().toString();

    } catch (MessageAccessException e) {

        trace.addWarning(“Can’t get information. Error: ” + e.getMessage());

    }

    // DLNG – messages that have been delivered

    // TBDL – no error, Messages to be delivered

    // HOLD – Held messages

    // NDLV – Messages with system errors

    // WAIT – Processing Backlog with Errors, Waiting messages

    return out;

    4)

    implement it in your message mapping and try it

    /wp-content/uploads/2014/09/pic05_551627.jpg

    5)

    enjoy result…

    /wp-content/uploads/2014/09/pic06_551628.jpg

    (0) 
  3. Michal Basl

    Unfortunately it’s not working me in 7.11 version 🙁

    There is exception like this:

    Exception:[java.lang.ClassCastException: class com.sap.engine.messaging.impl.api.APIAccessImpl:service:com.sap.aii.af.ms.svc@com.sap.engine.boot.loader.ResourceMultiParentClassLoader@79e70d8f@alive incompatible with interface com.sap.engine.interfaces.messaging.api.APIAccess:com.sap.aii.ibrep.server.mapping.rt.ArchiveClassLoader@f953ed2] in class com.crossgate.Basf.eBilling.FL_BASF method getMessageStatus[0050569b-007d-1ed4-90de-d01cb536728c, INBOUND, com.sap.aii.mappingtool.tf7.rt.Context@614f4d43]


    Problem is in this part: apiAccess = (APIAccess) obj;

    (0) 
      1. Iliya Kuznetsov

        Yes, there is an API for that:

           ctx = new InitialContext();

           o = ctx.lookup(“com.sap.engine.interfaces.messaging.api”);

           if (o==null) throw new StreamTransformationException(“APIAccess isn’t got”);

          

           s = o.getClass().getProtectionDomain().getCodeSource().getLocation().toString();

           tr.addInfo(“See file ” + s);

        At trace will be:See file file:/sapdata/usr_sap/SID/J00/j2ee/cluster/bin/services/com.sap.aii.af.ms.svc/lib/com.sap.aii.af.ms.svc_api.jar

        (for 7.31)

        (0) 
  4. Michal Basl

    Exception looks different but still here it is:

    Exception:[java.lang.ClassCastException: class com.sap.engine.messaging.impl.api.APIAccessImpl:service:com.sap.aii.af.ms.svc@com.sap.engine.boot.loader.ResourceMultiParentClassLoader@2e3ed883@alive incompatible with class com.sap.engine.messaging.impl.api.APIAccessImpl:com.sap.aii.ibrep.server.mapping.rt.ArchiveClassLoader@727af65a]

    I’m using right instance of APIAccessImpl class, but from different namespace, while running program is used Archive namespace.

    (0) 

Leave a Reply