Skip to Content

Prerequisites

You should have read this Weblogs to know about the SAP Java Connector (JCo) working as a client and even as a server:

Environment

  <pclass=sdnnormal>In the SAP R/3 system there is a RFC enabled Function Module which calles the original SAP Transaction via Batch Input. Unfortunately this Transaction sometimes pops up with a info message which is not put into the message table. This info message needs a SAP GUI to be displayed. Calling this Function from an web application lead into the Error “GUI not reached”. 

Solution

  To get around this problem I’ve found this solution: 

image

  • Create a RFC enabled Function Module “Z_BATCH_INPUT_PROXY” with the same interface as the Function Module “Z_BATCH_INPUT” and call “Z_BATCH_INPUT” with destination “JCOPROXY”
  • “JCOPROXY” is a destination created in Transaction “SM59” which connects to a JCo Server.
  • This JCo Server takes the Input from the “Z_BATCH_INPUT_PROXY” and calls the JCo Client which has the flag use_sapgui enabled.
  • Finaly the JCo client calls the RFC enabled Function Module “Z_BATCH_INPUT” which needs a SAP Gui to run successfully.

Sourcecode

The first file are the logon.properties which are used to keep the logon information out of the source code. Please adopt it to your enviroment:

jco.client.client=002
jco.client.user=its
jco.client.passwd=XXXXXXX
jco.client.ashost=appserver.hostname.domain
jco.client.sysnr=systemnumber
jco.client.lang=language
jco.client.abap_debug=0
jco.client.use_sapgui=1
jco.server.gwhost=gwhost.hostname.domain
jco.server.gwserv=gwservice
jco.server.progid=JCOPROXY

Next is the file OrderedProperties.java which comes with the JCo examples. This class is used to read the logon.properties file:

import java.util.*;
import java.io.*;
public class OrderedProperties extends java.util.Properties {
  ArrayList orderedKeys = new ArrayList();
  public OrderedProperties() {
    super();
  }
  public OrderedProperties(java.util.Properties defaults) {
    super(defaults);
  }
  public synchronized Iterator getKeysIterator() {
    return orderedKeys.iterator();
  }
  public static OrderedProperties load(String name)
                                  throws IOException {
    OrderedProperties props = null;
    java.io.InputStream is =
      OrderedProperties.class.getResourceAsStream(name);
    if ( is !=null ) {
      props = new OrderedProperties();
      props.load(is);
      return props;
    } else {
      if ( ! name.startsWith("/") ) {
        return load("/" + name);
      } else {
        throw new IOException("Properties could not be loaded.");
      }
    }
  }
  public synchronized Object put(Object key, Object value) {
    Object obj = super.put(key, value);
    orderedKeys.add(key);
    return obj;
  }
  public synchronized Object remove(Object key) {
    Object obj = super.remove(key);
    orderedKeys.remove(key);
    return obj;
  }
}

Now we come to the implementation of the JCo Server which receives the calls from the Proxy Function in R/3 which uses the destination “JCOPROXY”. The file name is myJCoServer.java:

/**
 * myJCoServer.java - Simple implementation of an (external RFC) server.
 * (c) Copyright by Gregor Wolf, 2004-2005
 * All rights reserved.
 */
import com.sap.mw.jco.*;
import java.util.*;
/**
 * @version 1.0
 * @author  Gregor Wolf
 */
public class myJCoServer
  implements JCO.ServerExceptionListener,
    JCO.ServerStateChangedListener,
    JCO.ServerErrorListener {
  /**
   *  This is the actual Server (Listener) object
   */
  static public class Server extends JCO.Server {
    public Server(String gwhost, String gwserv, String program_id, IRepository repos)
    {
      super(gwhost, gwserv, program_id, repos);
    }
    public Server(Properties prop, IRepository repos)
    {
      super(prop, repos);
    }
    protected boolean onCheckTID(String tid)
    {
      return true;
    }
    protected void onConfirmTID(String tid)
    {
    }
    protected void onCommit(String tid)
    {
    }
    protected void onRollback(String tid)
    {
    }
    /**
     *  Called upon an incoming requests
     */
    protected void handleRequest(JCO.Function function)
    {
      // Process incoming requests
      if (function.getName().equals("Z_BATCH_INPUT")) {
        myJCoClient client = new myJCoClient();
        JCO.ParameterList input  = function.getImportParameterList();
        JCO.ParameterList tables = function.getTableParameterList();
        // Convert input to XML
        String inputXML = input.toXML();
        // Convert tables to XML
        String tablesXML = tables.toXML();
        // Call JCo Client
        client.myJCoClientCall(inputXML, tablesXML);
        // Get Tables
        tablesXML = client.getTablesXML();
        // Fill the tables from XML
        JCO.ParameterList tablesFromXML = (JCO.ParameterList)tables.clone();
        // function.getTableParameterList();
        tablesFromXML.fromXML(tablesXML);
       
        JCO.Table rueckmeldungen = tables.getTable("Z_RUECKTAB");
        JCO.Table hinweise = tables.getTable("Z_HINWEISE");
        JCO.Table returntab = tables.getTable("RETURN");
       
        JCO.Table rueckmeldungenFromXML = tablesFromXML.getTable("Z_RUECKTAB");
        JCO.Table hinweiseFromXML = tablesFromXML.getTable("Z_HINWEISE");
        JCO.Table returntabFromXML = tablesFromXML.getTable("RETURN");
       
        rueckmeldungen.clear();
        hinweise.clear();
        returntab.clear();
       
        rueckmeldungen.copyFrom(rueckmeldungenFromXML);       
        hinweise.copyFrom(hinweiseFromXML);
        returntab.copyFrom(returntabFromXML);
        client.cleanUp();
      }
      // This will cause a short-dump in R/3 that indicates that we cannot
      // handle the request.
      else {
        // Otherwise
        throw new JCO.AbapException("NOT_SUPPORTED",
          "This service is not implemented by the external server");
      }
    }
  }
  /**
   *  Called if an exception was thrown anywhere in our server
   */
  public void serverExceptionOccurred(JCO.Server srv, Exception ex)
  {
    System.out.println("Exception in Server " + srv.getProgID() + ":\n" + ex);
    ex.printStackTrace();
  }
  /**
   *  Called if an error was thrown anywhere in our server
   */
  public void serverErrorOccurred(JCO.Server srv, Error err)
  {
    System.out.println("Error in Server " + srv.getProgID() + ":\n" + err);
    err.printStackTrace();
  }
 
  /**
   *  Simply prints server state changes
   */
  public void serverStateChangeOccurred(JCO.Server server, int old_state, int new_state)
  {
    System.out.print("Server " + server.getProgID() + " changed state from [");
    if ((old_state & JCO.STATE_STOPPED    ) != 0) System.out.print(" STOPPED ");
    if ((old_state & JCO.STATE_STARTED    ) != 0) System.out.print(" STARTED ");
    if ((old_state & JCO.STATE_LISTENING  ) != 0) System.out.print(" LISTENING ");
    if ((old_state & JCO.STATE_TRANSACTION) != 0) System.out.print(" TRANSACTION ");
    if ((old_state & JCO.STATE_BUSY       ) != 0) System.out.print(" BUSY ");
    System.out.print("] to [");
    if ((new_state & JCO.STATE_STOPPED    ) != 0) System.out.print(" STOPPED ");
    if ((new_state & JCO.STATE_STARTED    ) != 0) System.out.print(" STARTED ");
    if ((new_state & JCO.STATE_LISTENING  ) != 0) System.out.print(" LISTENING ");
    if ((new_state & JCO.STATE_TRANSACTION) != 0) System.out.print(" TRANSACTION ");
    if ((new_state & JCO.STATE_BUSY       ) != 0) System.out.print(" BUSY ");
    System.out.println("]");
  }
  // System IDs of the system that we gonna using be for dictionary calls
  String POOL_A = "SYSTEM_A";
  // The server objects that actually handles the request
  int MAX_SERVERS = 1;
  Server servers[] = new Server[MAX_SERVERS];
  /**
   *  Constructor. Creates a client pool, the repository and a server.
   */
  public myJCoServer()
  {
    try {
      IRepository repository;
 
      OrderedProperties logonProperties
        = OrderedProperties.load("/logon.properties");
     
      // Add a connection pool to a remote R/3 system A.
      // We will use this connected to dynamically
      // request dictionary information for incoming function calls.
      JCO.addClientPool(POOL_A,5,logonProperties);
 
      // Create repository for System A
      repository = JCO.createRepository("SYSTEM_A", POOL_A );
 
      // Create a new server and register it with system A
      servers[0] = new Server(logonProperties, repository);
 
      // Register ourselves such that we get exceptions from the servers
      JCO.addServerExceptionListener(this);
 
      // Register ourselves such that we get errors from the servers
      JCO.addServerErrorListener(this);
     
      // And we also want to know when the server(s) change their states
      // JCO.addServerStateChangedListener(this);
    }
    catch (Exception ex) {
      ex.printStackTrace();
    }
  }
  /**
   *  Start the server
   */
  public void startServers()
  {
    try {
      for (int i = 0; i < MAX_SERVERS; i++) {
        servers[i].start();
      }
    }
    catch (Exception ex) {
      System.out.println("Could not start servers !\n" + ex);
    }//try
  }
  /**
   *  Simple main program driver
   */
  public static void main(String[] argv)
  {
    myJCoServer obj = new myJCoServer();
    obj.startServers();
  }
}

At last we need the implementation of the JCo Client. The File name is myJCoClient.java:

/**
 * myJCoClient.java
 * (c) Copyright Gregor Wolf, 2004-2005
 * All rights reserved.
 */
import com.sap.mw.jco.*;
import java.util.*;
/**
 * @version 1.0
 * @author  Gregor Wolf, 2004
 */
public class myJCoClient {
  // Name of the ClientPool
  static final String POOL_NAME = "Pool";
  JCO.Client mConnection;
  // The repository we will be using
  IRepository repository;
  // Parameters
  private JCO.ParameterList input;
  private JCO.ParameterList tables;
  private String inputXML;
  private String tablesXML;
  
  public myJCoClient()
  {
    try {
      JCO.Pool pool = JCO.getClientPoolManager().getPool(POOL_NAME);
      if (pool == null) {
        OrderedProperties logonProperties =
          OrderedProperties.load("/logon.properties");
        JCO.addClientPool(POOL_NAME,  // pool name
                          5,          // maximum number of connections
                          logonProperties);  // properties
      }
      mConnection = JCO.getClient(POOL_NAME);
      // Create a new repository
      repository = JCO.createRepository("MYRepository", POOL_NAME);
    }
    catch (Exception ex) {
      ex.printStackTrace();
    }
  }
  protected void cleanUp() {
    JCO.removeClientPool(POOL_NAME);
  }
  public String getInputXML() {
    // System.out.println("getInputXML");
    return inputXML;
  }
  public String getTablesXML() {
    // System.out.println("tablesXML");
    return tablesXML;
  }
  // Retrieves and prints information about the remote system
  public void myJCoClientCall(String inputXMLin, String tablesXMLin)
  {
    JCO.Client client = null;
    try {
      // Get a function template from the repository
      IFunctionTemplate ftemplate = repository.getFunctionTemplate("Z_BATCH_INPUT");
      // if the function definition was found in backend system
      if(ftemplate != null) {
        // Create a function from the template
        JCO.Function function = ftemplate.getFunction();      
        // Fill in input parameters
        JCO.ParameterList input = function.getImportParameterList();
        JCO.ParameterList tables = function.getTableParameterList();
        // Fill the input parameters from XML
        input.fromXML(inputXMLin);
        // Fill the tables from XML
        tables.fromXML(tablesXMLin);
        JCO.Table rueckmeldungen = tables.getTable("Z_RUECKTAB");
        // Get a client from the pool
        client = JCO.getClient(POOL_NAME);
        // Call the function
        client.execute(function);
        // Return the input via XML
        inputXML = input.toXML();
        // Return the tables via XML
        tablesXML = tables.toXML();
      }
      else {
        System.out.println("Function Z_BATCH_INPUT not found in backend system.");
      }//if
    }
    catch (Exception ex) {
      System.out.println("Caught an exception: \n" + ex);
    }
    finally {
      // Release the client to the pool
      JCO.releaseClient(client);
    }
  }
}

Put this files all together in one directory and compile it with “javac myJCoServer.java”. Then you can start it with “java myJCoServer”. Test it out by running the Server on your Development system. When you have it running it’s time to run it as a service. I’ve used the Java Service Wrapper form Tanuki Software which can be used to make every Java Program run as a Windows Service.

To report this post you need to login first.

6 Comments

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

  1. Gaurav Berry
    Hi Gregor,

    i am getting these exceptions when applying your solution for Suppressing unwanted SAP GUI screens from BAPI/RFC when calling them from external system in background

    com.sap.mw.jco.JCO$Exception: (104) RFC_ERROR_SYSTEM_FAILURE: Session     1: Special character for ’empty field’ is /
            at com.sap.mw.jco.rfc.MiddlewareRFC$Client.nativeExecute(Native Method)
            at com.sap.mw.jco.rfc.MiddlewareRFC$Client.execute(MiddlewareRFC.java:871)
            at com.sap.mw.jco.JCO$Client.execute(JCO.java:2995)
            at com.sap.mw.jco.JCO$Client.execute(JCO.java:2669)
            at myJCoClient.myJCoClientCall(myJCoClient.java:95)
            at myJCoServer$Server.handleRequest(myJCoServer.java:65)
            at com.sap.mw.jco.JCO$Server.dispatchRequest(JCO.java:5409)
            at com.sap.mw.jco.rfc.MiddlewareRFC$Server.nativeListen(Native Method)
            at com.sap.mw.jco.rfc.MiddlewareRFC$Server.listen(MiddlewareRFC.java:1010)
            at com.sap.mw.jco.JCO$Server.listen(JCO.java:5205)
            at com.sap.mw.jco.JCO$Server.run(JCO.java:5139)
            at java.lang.Thread.run(Thread.java:595)

    any help will be appreciated…

    thanks in advance
    berry

    (0) 
  2. Gaurav Berry
    Hi Gregor,

    i am getting these exceptions when applying your solution for Suppressing unwanted SAP GUI screens from BAPI/RFC when calling them from external system in background

    com.sap.mw.jco.JCO$Exception: (104) RFC_ERROR_SYSTEM_FAILURE: Session     1: Special character for ’empty field’ is /
            at com.sap.mw.jco.rfc.MiddlewareRFC$Client.nativeExecute(Native Method)
            at com.sap.mw.jco.rfc.MiddlewareRFC$Client.execute(MiddlewareRFC.java:871)
            at com.sap.mw.jco.JCO$Client.execute(JCO.java:2995)
            at com.sap.mw.jco.JCO$Client.execute(JCO.java:2669)
            at myJCoClient.myJCoClientCall(myJCoClient.java:95)
            at myJCoServer$Server.handleRequest(myJCoServer.java:65)
            at com.sap.mw.jco.JCO$Server.dispatchRequest(JCO.java:5409)
            at com.sap.mw.jco.rfc.MiddlewareRFC$Server.nativeListen(Native Method)
            at com.sap.mw.jco.rfc.MiddlewareRFC$Server.listen(MiddlewareRFC.java:1010)
            at com.sap.mw.jco.JCO$Server.listen(JCO.java:5205)
            at com.sap.mw.jco.JCO$Server.run(JCO.java:5139)
            at java.lang.Thread.run(Thread.java:595)

    any help will be appreciated…

    thanks in advance
    berry

    (0) 
  3. Gaurav Berry
    Hi Gregor,

    i am getting these exceptions when applying your solution for Suppressing unwanted SAP GUI screens from BAPI/RFC when calling them from external system in background

    com.sap.mw.jco.JCO$Exception: (104) RFC_ERROR_SYSTEM_FAILURE: Session     1: Special character for ’empty field’ is /
            at com.sap.mw.jco.rfc.MiddlewareRFC$Client.nativeExecute(Native Method)
            at com.sap.mw.jco.rfc.MiddlewareRFC$Client.execute(MiddlewareRFC.java:871)
            at com.sap.mw.jco.JCO$Client.execute(JCO.java:2995)
            at com.sap.mw.jco.JCO$Client.execute(JCO.java:2669)
            at myJCoClient.myJCoClientCall(myJCoClient.java:95)
            at myJCoServer$Server.handleRequest(myJCoServer.java:65)
            at com.sap.mw.jco.JCO$Server.dispatchRequest(JCO.java:5409)
            at com.sap.mw.jco.rfc.MiddlewareRFC$Server.nativeListen(Native Method)
            at com.sap.mw.jco.rfc.MiddlewareRFC$Server.listen(MiddlewareRFC.java:1010)
            at com.sap.mw.jco.JCO$Server.listen(JCO.java:5205)
            at com.sap.mw.jco.JCO$Server.run(JCO.java:5139)
            at java.lang.Thread.run(Thread.java:595)

    any help will be appreciated…

    thanks in advance
    berry

    (0) 
  4. Ruhi Hira Sharma
    Hi

    I have a standalone java program, which is internally calling an SAP function using JCO 2.0.
    This SAP function is internally calling a tCode using ABAP4_CALL_TRANSACTION.
    I have set SAPGUI to 2.

    mConnection =
    JCO.createClient(“XXX”, “user”, “password”, “lang”, “host”, “num”, “”, “”);
    System.out.println(“SAPGUI set to 2”);
    mConnection.setSapGui(2);
    mConnection.setProperty(“jco.destination.name”, “SAPGUI”);
    mConnection.connect();

    SAP GUI is launched with the desired tCode on execution of this java program.
    But the issue is there are three sessions on SAP, when checked from SM04.
    ************************************
    550 USERNAME HOSTNAME 13.09.00 1 RFC 0
    550 USERNAME HOSTNAME TCODE 13.09.00 1 RFC 4
    550 USERNAME HOSTNAME 13.09.00 1 GUI 0
    ************************************
    The sessions are active even after JCO connection is disconnected and java program terminates.

    Can you please help on this.

    Thanks a lot

    Regards
    Ruhi Hira

    (0) 
  5. Ruhi Hira Sharma
    Hi

    I have a standalone java program, which is internally calling an SAP function using JCO 2.0.
    This SAP function is internally calling a tCode using ABAP4_CALL_TRANSACTION.
    I have set SAPGUI to 2.

    mConnection =
    JCO.createClient(“XXX”, “user”, “password”, “lang”, “host”, “num”, “”, “”);
    System.out.println(“SAPGUI set to 2”);
    mConnection.setSapGui(2);
    mConnection.setProperty(“jco.destination.name”, “SAPGUI”);
    mConnection.connect();

    SAP GUI is launched with the desired tCode on execution of this java program.
    But the issue is there are three sessions on SAP, when checked from SM04.
    ************************************
    550 USERNAME HOSTNAME 13.09.00 1 RFC 0
    550 USERNAME HOSTNAME TCODE 13.09.00 1 RFC 4
    550 USERNAME HOSTNAME 13.09.00 1 GUI 0
    ************************************
    The sessions are active even after JCO connection is disconnected and java program terminates.

    Can you please help on this.

    Thanks a lot

    Regards
    Ruhi Hira

    (0) 
  6. Ruhi Hira Sharma
    Hi

    I have a standalone java program, which is internally calling an SAP function using JCO 2.0.
    This SAP function is internally calling a tCode using ABAP4_CALL_TRANSACTION.
    I have set SAPGUI to 2.

    mConnection =
    JCO.createClient(“XXX”, “user”, “password”, “lang”, “host”, “num”, “”, “”);
    System.out.println(“SAPGUI set to 2”);
    mConnection.setSapGui(2);
    mConnection.setProperty(“jco.destination.name”, “SAPGUI”);
    mConnection.connect();

    SAP GUI is launched with the desired tCode on execution of this java program.
    But the issue is there are three sessions on SAP, when checked from SM04.
    ************************************
    550 USERNAME HOSTNAME 13.09.00 1 RFC 0
    550 USERNAME HOSTNAME TCODE 13.09.00 1 RFC 4
    550 USERNAME HOSTNAME 13.09.00 1 GUI 0
    ************************************
    The sessions are active even after JCO connection is disconnected and java program terminates.

    Can you please help on this.

    Thanks a lot

    Regards
    Ruhi Hira

    (0) 

Leave a Reply