{"id":323,"date":"2011-02-20T21:09:19","date_gmt":"2011-02-20T20:09:19","guid":{"rendered":"http:\/\/www.capri-soft.de\/blog\/?p=323"},"modified":"2018-03-05T16:37:53","modified_gmt":"2018-03-05T15:37:53","slug":"sap-zugriff-auf-funktionsbausteine-bapis-mit-dem-java-connector","status":"publish","type":"post","link":"https:\/\/www.capri-soft.de\/blog\/?p=323","title":{"rendered":"SAP und JAVA: Zugriff auf Funktionsbausteine \/ BAPIs mit dem Java Connector"},"content":{"rendered":"<h1>Aufgabenstellung<\/h1>\n<p>Es soll auf Daten aus dem SAP System zugegriffen werden, ohne die Datenbank direkt anzusprechen.<\/p>\n<h1>Ansatz<\/h1>\n<p>Durch die Verwendung des Java-Connectors (JCo) werden Funktionsbausteine \/ BAPIs als SAP Schnittstellen verwendet. Die Funktionsbausteine k\u00f6nnen \u00fcber die SAP GUI mit dem BAPI-Explorer gesucht und mit der TA 37 getestet werden. Der nachfolgende Artikel besch\u00e4ftigt sich mit dem Aufruf von einem Java-Server. Der JCo kann im Market Place von SAP kostenlos heruntergeladen werden.<\/p>\n<h1>L\u00f6sung<\/h1>\n<h2>Remote Function Call (techn. RPC)<\/h2>\n<p>Ein Remote Function Call (RFC) ist die SAP-Implementierung von Remote Procedure Calls (RPC). \u00dcber einen RFC lassen sich Funktionsbausteine, bzw. BAPI&#8217;s aufrufen. <\/p>\n<p>Ein RFC verwendet die Kommunikationsregeln des CPI-C-Protokolls, welches auf TCP\/IP oder LU 6.2 basiert. LU 6.2 war dabei das Kommunikationsprotokoll von R\/2-Mainframe-Systemen und wurde bei R\/3 durch den einheitlichen TCP\/IP-Standard ersetzt.<\/p>\n<p>RFC&#8217;s nehmen ausschlie\u00dflich Call-By-Value-Parameter entgegen, da die \u00dcbergabe von Zeigern und Speicheradressen hier keinen Sinn macht. In einem fremden System w\u00fcrde die Speicheradresse auf einen Speicher-Bereich zeigen, in dem keine oder Daten von anderen Anwendungen vorhanden sind. <\/p>\n<h2>Funktionsweise des Java Connectors (JCo)<\/h2>\n<p>Der Java Connector unterst\u00fctzt den Aufruf von RFC&#8217;s, bzw. BAPIs aus einer externen Java-Umgebung (SAP-inbound-call), sowie den Aufruf externer JAVA-Funktionalit\u00e4ten aus ABAP-Programmen heraus (SAP-outbound-call). F\u00fcr die letztgenannte Variante existiert im Example-Verzeichnis des JCo ein Beispiel, in dem ein JCo-Server implementiert wird. Der JCo-Server muss dem SAP-System \u00fcber die Transaktion SM59 bekanntgemacht werden.<\/p>\n<p>Bei einem SAP-Inbound-Call ist die Vorgehensweise die folgende:<\/p>\n<p>1.) Anmeldung der Java-Applikation am R\/3-System<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nJCO.Client Conection = JCO.createClient(Mandant,\r\n                                        Username,\r\n                                        Password,\r\n                                        Language,\r\n                                        Hostname,\r\n                                        Systemnummer);\r\n\r\nConnection.connect();\r\n<\/pre>\n<p>2.) Herunterladen des Repository f\u00fcr den Funktionsbaustein<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nIRepository rep = JCO.createRepository(&quot;MyRepository&quot;, Connection);\r\nIFunctionTemplate template = rep.getFunctionTemplate(&quot;BAPI_NAME&quot;);\r\nJCO.Function funktion = new JCO.Function(template);\r\n<\/pre>\n<p>3.) Holen einer Referenz auf die \u00dcbergabeparameter<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nJCO.ParameterList import = funktion.getImportParameterList();\r\nJCO.ParameterList table = funktion.getTableParameterList();\r\n<\/pre>\n<p>4.) Bef\u00fcllen des Bausteins <\/p>\n<p>5.) Funktionsbaustein ausf\u00fchren<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nConnection.execute(funktion);\r\n<\/pre>\n<p>6.) Hole Referenz auf R\u00fcckgabeparameter<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nJCO.ParameterList export = funktion.getExportParameterList();\r\nJCO.ParameterList table = funktion.getTableParameterList();\r\n<\/pre>\n<p>7.) Auslesen des Bausteins <\/p>\n<p>Es werden synchrone (sRFC), asynchrone (aRFC) und transaktionale Aufrufe (tRFC, qRFC), sowie Connection-Pooling unterst\u00fctzt (auf JAVA- wie auf ABAP-Seite).<\/p>\n<p>SAP lobt zwar die Plattformunabh\u00e4ngigkeit des Connectors, jedoch st\u00f6\u00dft man bei einfachem Kopieren des Bytecodes auf Probleme, da hier eine plattformabh\u00e4ngige Bibliotheksdatei gekapselt wird, die bei h\u00f6heren Releases nicht mehr funktioniert. Unter Windows wird die Datei librfc32.dll und unter Linux die Datei librfccm.so gekapselt.<\/p>\n<p>Durch die Kapselung der Datei ist es ohne weiteres m\u00f6glich, Konnektoren f\u00fcr nicht unterst\u00fctzte Programmiersprachen zu implementieren.<\/p>\n<p>Ein Tutorial der Zeitschrift &#8222;Der Entwickler&#8220;, welches Online zur Verf\u00fcgung steht, zeigt durch Verwendung dieser Bibliothek, wie man Delphi an SAP-Systeme andocken kann. Der Artikel tr\u00e4gt den Namen &#8222;Delphi goes SAP&#8220;. Da es f\u00fcr Delphi keine Konnektoren wie den Java Connector gibt, ist die Kapselung dieser Datei notwendig.<\/p>\n<h1>Parameter von Funktionsbausteinen<\/h1>\n<p>Da die meisten SAP-Anwendungen im ABAP-Stack implementiert worden, greift man mit dem JAVA Connector haupts\u00e4chlich auf remotef\u00e4hige Funktionsbausteine zu. Diesen werden entweder ausgef\u00fcllte Tabellen, oder Import-Parameter zur Verarbeitung \u00fcbergeben. Als Ausgabe liefert ein Funktionsbaustein Fehler-Parameter, Export-Parameter, neue Tabellen oder auch die \u00fcbergebenen Tabellen mit neuen Werten zur\u00fcck. Hierf\u00fcr ist es notwendig den syntaktischen Aufbau von JCO-Syntax zu kennen. <\/p>\n<h2>Import-Parameter<\/h2>\n<p>Import-Parameter kann man sich wie einfache \u00dcbergabeparametern aus bekannten Programmiersprachen vorstellen. Ein Import-Parameter entspricht einem Feld, was einen Datentyp beinhaltet (Char, Integer, String, Double&#8230;). Es kann keine Array&#8217;s, Listen oder Tabellen entgegennehmen.<\/p>\n<p>SAP kennzeichnet hauseigene Funktionsbausteine mit einem vorangehenden I f\u00fcr &#8222;Import&#8220;. Mit der Transaktion SE16 ist es m\u00f6glich sich die notwendigen Import-Parameter anzusehen. <\/p>\n<p>Nicht alle Import-Parameter sind erforderlich, es gibt auch optionale Parameter. Nicht jeder Funktionsbaustein hat Import-Parameter.<\/p>\n<p>Der nachstehende Code zeigt, wie mit Hilfe des JAVA Connectors der Funktionsbaustein &#8222;CFX_API_USER_GETDETAIL&#8220;, der die Detaildaten eines cFolders-Benutzers zur\u00fcckgibt bef\u00fcllt wird:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\npublic String gibListeVonUsern()\r\n{\r\n  IRepository repository = JCO.createRepository(&quot;MYRepository&quot;, client);\r\n  IFunctionTemplate ftemplate = repository\r\n .getFunctionTemplate(&quot;CFX_API_USER_GETDETAIL&quot;);\r\n  Function func = ftemplate.getFunction();\r\n\r\n  JCO.ParameterList input = func.getImportParameterList();\r\n  input.setValue(&quot;KARPBJ01&quot;, &quot;I_USER_ID&quot;);\r\n\r\n  \/\/ Funktion aufrufen\r\n  client.execute(func);\r\n  (...)\r\n}\r\n<\/pre>\n<h2>Export-Parameter<\/h2>\n<p>Nachdem die Funktion ausgef\u00fchrt wurde, kann \u00fcber die Export-Parameter iteriert werden um die R\u00fcckgabewerte auszulesen. Dazu hat die Klasse ParameterList die Methode getFieldCount(), welche die Anzahl der R\u00fcckgabeparameter zur\u00fcckliefert. Die Methode getString(index) erm\u00f6glich \u00fcber den inkrementellen Index die Iteration mit einer Schleife. Dadurch lassen sich alle Parameter dynamisch auslesen.<\/p>\n<p>Nachfolgend wird aus der aufgerufenden Funktion \u00fcber die Export-Parameterliste iteriert und das Ergebnis an den String &#8222;informationen&#8220; angehangen.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\r\npublic String gibListeVonUsern()\r\n{\r\n  (...) \/\/Hier war der Funktionsaufruf\r\n\r\n  JCO.ParameterList output = func.getExportParameterList();\r\n\r\n  for (int i = 0; i &lt; output.getFieldCount(); i++)\r\n  {\r\n    informationen = informationen + output.getString(i) + &quot;\\n&quot;;\r\n  }\r\n  return informationen;\r\n}\r\n\r\n<\/pre>\n<h2>Changing-Parameter<\/h2>\n<p>Im Gegensatz zu Import- und Export-Parametern funktionieren Changing-Parameter in beide Richtungen (bidirektional). Der Aufruf ist dabei Call-By-Reference-\u00e4hnlich, da sich nach dem Ausf\u00fchren des Funktionsbausteins mit dem Befehl client.execute(func); der Wert im Feld \u00e4ndern kann. Das Bef\u00fcllen und auslesen funktioniert dabei wie bei den Import- und Export-Parametern.<\/p>\n<h2>Table-Parameter<\/h2>\n<p>Table-Parameter sind bidirektional. Die Referenz auf eine Tabelle kann geholt werden, bevor die Funktion ausgef\u00fchrt wurde. Hat man die Referenz auf die Tabelle, so l\u00e4sst sich diese folgenderma\u00dfen bef\u00fcllen:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\r\n  \/\/ Iteration \u00fcber einen Vector\r\n  for (int i = 0; i &lt; vector.size(); i++)\r\n  {\r\n     \/\/ Neue Zeile an Tabelle anh\u00e4ngen und auf\r\n     \/\/ neue Zeile wechseln\r\n     table.appendRow();\r\n\r\n     \/\/ schreibe in erste Spalte\r\n     table.setValue((String)vector.get(i),0);\r\n\r\n     \/\/ schreibe in zweite Spalte\r\n     table.setValue((String)vector.get(i),1);\r\n  }\r\n\r\n<\/pre>\n<p>Nachdem eine Funktion ausgef\u00fchrt wurde, also nachdem Connection.execute(funktion); ausgef\u00fchrt wurde, kann eine neue Tabelle zur\u00fcckgeliefert werden, oder eine bereits bef\u00fcllte Tabelle neue Werte beinhalten. <\/p>\n<p>Um \u00fcber eine R\u00fcckgabetabelle zu iterieren, gibt es die Funktion setRow(index). Das folgende Beispiel zeigt die Suche nach einem bestimmten String in der 3. Spalte und liefert das Feld &#8222;ID&#8220; zur\u00fcck:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\r\n  String rueckgabe = null;\r\n  for (int i=0;i&lt;outputtabelle.getNumRows();i++)\r\n  {\r\n    outputtabelle.setRow(i);\r\n\r\n    if (outputtabelle.getString(2).equals(suche) )\r\n    {\r\n      rueckgabe = outputtabelle.getString(&quot;ID&quot;);\r\n    }\r\n  }\r\n\r\n<\/pre>\n<p>Wie ersichtlich wird, l\u00e4sst sich die Spalte nicht nur anhand des inkrementellen Indexes ansprechen, sondern auch \u00fcber den Spaltennamen. <\/p>\n<p>In manchen F\u00e4llen ist es n\u00f6tig eine eigene Tabelle zu erzeugen und diese an einen Funktionsbaustein zu \u00fcbergeben. Zum Beispiel funktioniert die Zuweisung einer bef\u00fcllten Ergebnistabelle an eine \u00dcbergabetabelle nicht, in diesem Fall muss man die Daten in einer Schleife einfach rauskopieren. <\/p>\n<p>Eine eigene Tabellendefinition erzeugt man in diesem Fall so:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\r\n  JCO.MetaData smeta  = new JCO.MetaData(&quot;DIS&quot;);\r\n\r\n  smeta.addInfo(&quot;DOKAR&quot;,  JCO.TYPE_STRING,  3,  0, 0);\r\n  smeta.addInfo(&quot;DOKVR&quot;,  JCO.TYPE_STRING ,   2, 0, 0);\r\n  smeta.addInfo(&quot;DOKTL&quot;,  JCO.TYPE_STRING ,   3, 0, 0);\r\n  smeta.addInfo(&quot;DOKNR&quot;,  JCO.TYPE_STRING ,   3, 0, 0);\r\n\r\n  JCO.Structure structure = new JCO.Structure(smeta); \r\n  JCO.Table table = new JCO.Table(structure);\r\n\r\n<\/pre>\n<h2>Struktur-Parameter<\/h2>\n<p>Strukturen geh\u00f6ren zu den Tabellen-Typ-Parametern und sind Sonderf\u00e4lle. Eine Struktur kann innerhalb einer Tabelle, in Import- oder Export-Parametern auftreten. Hierbei handelt es sich lediglich um eine weitere Aufteilung innerhalb eines einzigen Feldes. <\/p>\n<p>Der folgende Code zeigt, wie eine Referenz auf eine Inputstruktur und auf einen normalen Import-Parameter geholt wird . <\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\r\nJCO.Structure struktur =\r\nfunc.getImportParameterList().getStructure(&quot;SELECT_DOCUMENTDATA&quot;);\r\nJCO.ParameterList inputdata = func.getImportParameterList();\r\nstruktur.setValue(art, &quot;DOCUMENTTYPE&quot;);\r\ninputdata.setValue(&quot;X&quot;, &quot;GETCLASSIFICATION&quot;);\r\nOutput.execute(funktion);\r\n\r\n<\/pre>\n<p>Fortsetzung folgt &#8230;<\/p>\n<iframe src=\"http:\/\/www.facebook.com\/plugins\/like.php?href=https%3A%2F%2Fwww.capri-soft.de%2Fblog%2F%3Fp%3D323&amp;layout=standard&amp;show_faces=true&amp;width=450&amp;action=like&amp;colorscheme=light\" scrolling=\"no\" frameborder=\"0\" allowTransparency=\"true\" style=\"border:none; overflow:hidden; width:450px;margin-top:5px;\"><\/iframe>","protected":false},"excerpt":{"rendered":"<p>Aufgabenstellung Es soll auf Daten aus dem SAP System zugegriffen werden, ohne die Datenbank direkt anzusprechen. Ansatz Durch die Verwendung des Java-Connectors (JCo) werden Funktionsbausteine \/ BAPIs als SAP Schnittstellen verwendet. Die Funktionsbausteine k\u00f6nnen \u00fcber die SAP GUI mit dem BAPI-Explorer gesucht und mit der TA 37 getestet werden. Der nachfolgende Artikel besch\u00e4ftigt sich mit &hellip; <a href=\"https:\/\/www.capri-soft.de\/blog\/?p=323\" class=\"more-link\"><span class=\"screen-reader-text\">SAP und JAVA: Zugriff auf Funktionsbausteine \/ BAPIs mit dem Java Connector<\/span> weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[15,9],"tags":[],"class_list":["post-323","post","type-post","status-publish","format-standard","hentry","category-java","category-sap"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p4yGeN-5d","jetpack_likes_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=\/wp\/v2\/posts\/323","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=323"}],"version-history":[{"count":5,"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=\/wp\/v2\/posts\/323\/revisions"}],"predecessor-version":[{"id":325,"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=\/wp\/v2\/posts\/323\/revisions\/325"}],"wp:attachment":[{"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=323"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=323"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=323"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}