{"id":1518,"date":"2018-04-06T13:23:05","date_gmt":"2018-04-06T13:23:05","guid":{"rendered":"http:\/\/dlang.org\/blog\/?p=1518"},"modified":"2021-10-08T11:04:31","modified_gmt":"2021-10-08T11:04:31","slug":"d-goes-business","status":"publish","type":"post","link":"https:\/\/dlang.org\/blog\/2018\/04\/06\/d-goes-business\/","title":{"rendered":"D Goes Business"},"content":{"rendered":"<p><em>A long-time contributor to the D community, Kai Nacke is the author of &#8216;<a href=\"https:\/\/www.packtpub.com\/web-development\/d-web-development\">D Web Development<\/a>&#8216; and the maintainer of <a href=\"https:\/\/wiki.dlang.org\/LDC\">LDC<\/a>, the LLVM D Compiler. Be sure to catch Kai at <a href=\"http:\/\/dconf.org\/2018\/index.html\">DConf 2018 in Munich<\/a>, May 2 &#8211; 5, where he&#8217;ll be speaking about &#8220;<a href=\"http:\/\/dconf.org\/2018\/talks\/nacke.html\">D for the Blockchain<\/a>&#8220;.<\/em><\/p>\n<hr \/>\n<p>Many companies run their business processes on <a href=\"https:\/\/www.sap.com\/index.html\">an SAP system<\/a>. Often other applications need to access the SAP system because they provide data or request some calculation.\u00a0There are many ways to achieve this\u2026 Let\u2019s use D for it!<\/p>\n<p>&nbsp;<\/p>\n<h3 id=\"thesdkandthedbinding\">The SDK and the D binding<\/h3>\n<p><img loading=\"lazy\" class=\"alignleft size-full wp-image-181\" src=\"http:\/\/dlang.org\/blog\/wp-content\/uploads\/2016\/08\/d6.png\" alt=\"\" width=\"200\" height=\"200\" \/><\/p>\n<p>As an SAP customer you can download <a href=\"https:\/\/support.sap.com\/en\/temp\/connectors\/nwrfcsdk.html\">the SAP NetWeaver Remote Function Call SDK<\/a>. You can call RFC-enabled functions in the SAP system from a native application. Conversely, it is possible from an ABAP program to call a function in a native program. The API documentation for the library is available as a separate download. I recommend downloading it together with the library.<\/p>\n<p>The C\/C++ interface is well structured but can be very tedious to use. That\u2019s why I not only <a href=\"https:\/\/github.com\/redstar\/sapnwrfc-d\">created a D binding for the library<\/a> but also used some D magic to make the developer\u2019s life much easier. I introduced the following additions:<\/p>\n<ul>\n<li>Most functions have a parameter of type <code>RFC_ERROR_INFO<\/code>. As the name implies, this is only needed in case of an error. For each of these functions a new function is generated without the <code>RFC_ERROR_INFO<\/code> parameter and the return type <code>RFC_RC<\/code> changed to <code>void<\/code>. Instead, a <code>SAPException<\/code> is thrown in case of error.<\/li>\n<li>Functions named <code>RfcGet*Count<\/code> now return a <code>size_t<\/code> value instead of using an <code>out<\/code> parameter. This is possible because of the above step which changed the return type to <code>void<\/code>.<\/li>\n<li>Functions named <code>Rfc*ByIndex<\/code> use a <code>size_t<\/code> parameter for the index, thus better integrating with D.<\/li>\n<li>Functions which have a pointer and length value now accept a D array instead.<\/li>\n<li>Use of pointers to zero-terminated UTF\u201316 strings is replaced with <code>wstring<\/code> type parameters.<\/li>\n<\/ul>\n<p>Using the library is easy, just add<\/p>\n<pre>dependency \"sapnwrfc-d\"<\/pre>\n<p>to <a href=\"https:\/\/code.dlang.org\/package-format?lang=sdl\">your <code>dub.sdl<\/code> file<\/a>. One caveat: the libraries provided by the SAP package must be installed in such a way that the linker can find them. On Windows, you can add the path to the <code>lib<\/code> folder of the SDK to the <code>LIB<\/code> and <code>PATH<\/code> environment variables.<\/p>\n<h3 id=\"anexampleapplication\">An example application<\/h3>\n<p>Let\u2019s create an application calling a remote-enabled function on the SAP system. I use the <code>DATE_COMPUTE_DAY<\/code> function because it is simple but still has import and export parameters. This function takes a date (a string of format \u201cYYYYMMDD\u201d) and returns the weekday as a number (1 = Monday, 2 = Tuesday and so on).<\/p>\n<p>The application needs two parameters: the system identifier of the SAP system and the date. The system identifier denotes the destination for the RFC call. The parameters for the connection must be in the <code>sapnwrfc.ini<\/code> file, which must be located in the same folder as the application executable. An invocation of the application using the SAP system X01 looks like this:<\/p>\n<pre>D:\\OpenSource\\sapnwrfc-example&gt;sapnwrfc-example.exe X01 20180316\r\nDate 20180316 is day 5<\/pre>\n<p>First, <a href=\"https:\/\/code.dlang.org\/getting_started\">create the application with DUB<\/a>:<\/p>\n<pre>D:\\OpenSource&gt;dub init sapnwrfc-example\r\nPackage recipe format (sdl\/json) [json]: sdl\r\nName [sapnwrfc-example]:\r\nDescription [A minimal D application.]: An example rfc application\r\nAuthor name [Kai]: Kai Nacke\r\nLicense [proprietary]:\r\nCopyright string [Copyright \u00a9 2018, Kai Nacke]:\r\nAdd dependency (leave empty to skip) []: sapnwrfc-d\r\nAdded dependency sapnwrfc-d ~&gt;0.0.5\r\nAdd dependency (leave empty to skip) []:\r\nSuccessfully created an empty project in 'D:\\OpenSource\\sapnwrfc-example'.\r\nPackage successfully created in sapnwrfc-example\r\n\r\nD:\\OpenSource&gt;<\/pre>\n<p>Let\u2019s edit the application in <code>source\\app.d<\/code>. Since this is only an example application, I\u2019ve put all the code into the <code>main()<\/code> function. In order to use the library you simply import the <code>sapnwrfc<\/code> module. Most functions can throw a <code>SAPException<\/code>, so you want to wrap them in a <code>try<\/code> block.<\/p>\n<pre class=\"prettyprint lang-d\">import std.stdio;\r\nimport sapnwrfc;\r\n\r\nint main(string[] args)\r\n{\r\n    try\r\n    {\r\n        \/\/ Put your code here\r\n    }\r\n    catch (SAPException e)\r\n    {\r\n        writefln(\"Error occured %d %s\", e.code, e.codeAsString);\r\n        writefln(\"'%s'\", e.message);\r\n        return 100;\r\n    }\r\n    return 0;\r\n}<\/pre>\n<p>The library uses only UTF\u201316. Like the C\/C++ version, the alias <code>cU()<\/code> can be used to create a zero-terminated UTF\u201316 string from a D <code>string<\/code>. I convert the command line parameters first:<\/p>\n<pre class=\"prettyprint lang-d\">    auto dest = cU(args[1]);\r\n    auto date = cU(args[2]);<\/pre>\n<p>Now initialize the library. Most important, this function loads the <code>sapnwrfc.ini<\/code> file and initializes the environment. If this call is missing then it is implicitly done inside the library. Nevertheless, I recommend calling the function. It is possible that I will add more functionality to this function.<\/p>\n<pre class=\"prettyprint lang-d\">    RfcInit();<\/pre>\n<p>The next step is to open a connection to the SAP system. Since the connection parameters are in the <code>sapnwrf.ini<\/code> file, it is only necessary to provide the destination. In your own application you do not need to use the <code>sapnwrf.ini<\/code> file. You can provide all parameters in the <code>RFC_CONNECTION_PARAMETER[]<\/code> array which is passed to the <code>RfcOpenConnection()<\/code> function.<\/p>\n<pre class=\"prettyprint lang-d\">    RFC_CONNECTION_PARAMETER[1] conParams = [ { \"DEST\"w.ptr, dest } ];\r\n    auto connection = RfcOpenConnection(conParams);\r\n    scope(exit) RfcCloseConnection(connection);<\/pre>\n<p>Please note the D features used here. A string literal is always zero-terminated, therefore there is no need to use <code>cU()<\/code> on the <code>\"DEST\"w<\/code> literal. With <a href=\"https:\/\/tour.dlang.org\/tour\/en\/gems\/scope-guards\">the scope guard<\/a>, I make sure that the connection is closed at the end of the block.<\/p>\n<p>Before you can make an RFC call, you have to retrieve the function meta data (function description) and create the function from it.<\/p>\n<pre class=\"prettyprint lang-d\">    auto desc = RfcGetFunctionDesc(connection, \"DATE_COMPUTE_DAY\"w);\r\n    auto func = RfcCreateFunction(desc);\r\n    scope(exit) RfcDestroyFunction(func);<\/pre>\n<p>The <code>RfcGetFunctionDesc()<\/code> calls the SAP system to look up the meta data. The result is cached to avoid a network round trip each time you invoke this function. The implication is that the remote user needs the right to perform the look up. If this step fails with a security-related error, you should talk to your SAP administrator and review the rights of the remote user.<\/p>\n<p>The <code>DATE_COMPUTE_DAY<\/code> function has one import parameter, <code>DATE<\/code>. To pass a parameter you call one of the <code>RfcSetXXX()<\/code> or <code>RfcSetXXXByIndex()<\/code> functions. The difference is that the first variant uses the parameter name (here: <code>\"DATE\"<\/code>) or the index of the parameter in the signature (here: <code>1<\/code>). I often use the named parameter because the resulting code is much more readable. The date data type expects an 8 character UTF\u201316 array.<\/p>\n<pre class=\"prettyprint lang-d\">    RfcSetDate(func, \"DATE\", date[0..8]);<\/pre>\n<p>Now the function can be called:<\/p>\n<pre class=\"prettyprint lang-d\">    RfcInvoke(connection, func);<\/pre>\n<p>The computed weekday is returned in the export parameter <code>DAY<\/code>. There is a set of <code>RfcGetXXX()<\/code> and <code>RfcGetXXXByIndex()<\/code> functions to retrieve the value.<\/p>\n<pre class=\"prettyprint lang-d\">    wchar[1] day;\r\n    RfcGetChars(func, \"DAY\", day);<\/pre>\n<p>Let\u2019s print the result:<\/p>\n<pre class=\"prettyprint lang-d\">    writefln(\"Date %s is weekday %s\", date[0..8], day);<\/pre>\n<p>Congratulations! You\u2019ve finished your first RFC call.<\/p>\n<p>Build the application with <code>dub build<\/code>. Before you can run the application you still need to create the <code>sapnwrfc.ini<\/code> file. This looks like:<\/p>\n<pre>DEST=X01\r\nMSHOST=x01.your.domain\r\nGROUP=PUBLIC\r\nCLIENT=001\r\nUSER=kai\r\nPASSWD=secret\r\nLANG=EN<\/pre>\n<p>The SDK contains a commented <code>sapnwrfc.ini<\/code> file in the <code>demo<\/code> folder. If you are on Windows and your system still uses SAP GUI with the (deprecated) <code>saplogon.ini<\/code> file, then you can use the <code>createini<\/code> example application from my bindings library to convert the <code>saplogon.ini<\/code> file into the <code>sapnwrfc.ini<\/code> file.<\/p>\n<h3 id=\"summary\">Summary<\/h3>\n<p>Calling an RFC function of an SAP system with D is very easy. D features like support for UTF\u201316 strings, scope guards, and exceptions make the source quite readable. The presented example application is part of the D bindings library and can be downloaded from GitHub at <a href=\"https:\/\/github.com\/redstar\/sapnwrfc-d\">https:\/\/github.com\/redstar\/sapnwrfc-d<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Many companies run their business processes on an SAP system. Often other applications need to access the SAP system because they provide data or request some calculation. There are many ways to achieve this\u2026 Let\u2019s use D for it!<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[26,9],"tags":[],"_links":{"self":[{"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/posts\/1518"}],"collection":[{"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/comments?post=1518"}],"version-history":[{"count":3,"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/posts\/1518\/revisions"}],"predecessor-version":[{"id":1524,"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/posts\/1518\/revisions\/1524"}],"wp:attachment":[{"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/media?parent=1518"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/categories?post=1518"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dlang.org\/blog\/wp-json\/wp\/v2\/tags?post=1518"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}