Develop Web Service Client in JDE OneWorld By Gan, Li Da | 06 Jul 2010 Background We knew that E812 and E900 is web-service ready and they are allow to consume web service via BSSV object. But, how are about other versions of JDE, such as OneWorld? Is it really that they totally don’t have chance to use any web service up in the magic cloud? But I changed my opinion after knowing toolkit gSOAP which is an open source C/C++ implementation for web service and client applications. Technologies In my solution, the following technologies are involved: 1. JDE APPL In my sample applications, I am going to develop a simple interactive application which allows user enter and submit 2 numeric values to web service for the processing and a numeric result will be returned. 2. C BSFN JDE APPL is unable to call a 3rd party DLL without going through a BSFN. So a C BSFN will be developed to dynamically load a custom DLL. 3. gSOAP Web Service (WS) Client (in VC++ DLL) The main engine behind the whole solution that web-service-enable our JDE applications. I will use gSOAP toolkit to generate web service proxy/stub files and use them to develop WS client in VC++ DLL. 4. Java Web Service (published by Oracle OC4J) To eliminate any network problem, such as firewall blocking, I will setup an Oracle OC4J within LAN and use it to publish a simple Java Web Service. Solution 1 User enters values for Number 1 and Number 2, then click button to fire business function GSOAPBSFN2 which loads a 3rd party DLL vcgsoap2.dll into memory dynamically and pass in Number 1 and Number 2 to the DLL’s public function. Through web service proxy using open source gSOAP implementation, vcgsoap2.dll consumes Java web service Calc1WSSoapHttp published by OCJ4 running on my other machine. vcgsoap2.dll pass in the value of Number 1 and Number 2 and the result is returned from web service. vcgsoap2.dll pass the result back to business function GSOAPBSFN2 which returns and displays the value at the Result field. Development 1. Develop and deploy Java WS . First, download JDeveloper Studio. I am using version 10.1.3.5 which has much smaller file size than the latest version. Oracle JDeveloper 11g http://www.oracle.com/technology/software/products/jdev/htdocs/soft11.html Oracle JDeveloper (10.1.3.5) http://www.oracle.com/technology/software/products/jdev/htdocs/soft10135.html (For this version, just unzip it to a directory. No installation required.) Read the tutorial below to learn how to use JDeveloper to create and deploy a Java web service: http://www.oracle.com/technology/obe/obe1013jdev/10131/devdepandmanagingws/d evdepandmanagingws.htm Create a simple Java Class as following: 2 After create and deploy a web service on the Java class above, you should see a new web service published under OC4J Test the web service. Click on Service Description link and rememeber/save the WSDL address which will be used during gSOAP web service client development. 3 2. Develop JDE BSFN First, create a DSTR for the new BSFN Next we create the BSFN itself and attach the new Data Structure to it. Following general OneWorld procedures generate the skeleton and paste the typedef into the header. 4 The purpose of this BSFN is to be a pass-through for its DSTR to the VC++ DLL. Please see the BSFN code on the page 6. 3. Develop JDE APPL Program the push button to call the new BSFN created above as the following: 5 JDEBFRTN (ID) JDEBFWINAPI GSOAPBSFN2 (LPBHVRCOM lpBhvrCom, LPVOID lpVoid, LPDSD55GSOAPB2 lpDS) { /************************************************************************ * Declare structures ************************************************************************/ // Declare function pointer structure. Must use __cdecl calling convention. typedef void (__cdecl *PFNDLL)(LPBHVRCOM ,LPVOID, LPDSD55GSOAPB2); /************************************************************************ * Declare pointers ************************************************************************/ HMODULE hLibrary; PFNDLL lpfndllTemplate; /************************************************************************ * Check for NULL pointers ************************************************************************/ if ((lpBhvrCom == (LPBHVRCOM) NULL) || (lpVoid == (LPVOID) NULL) || (lpDS == (LPDSD55GSOAPB2) NULL)) { jdeErrorSet (lpBhvrCom, lpVoid, (ID) 0, "4363", (LPVOID) NULL); return ER_ERROR; } /************************************************************************ * Main Processing ************************************************************************/ // Open the dll. If NULL is returned, the DLL could not be opened. vcgsoap2.dll is the DLL we are going to develop later. if((hLibrary = LoadLibrary(TEXT("vcgsoap2.dll")))==NULL) return(ER_ERROR); // Get the memory location of the Entry Point. If NULL is returned, there is no // such routine in the DLL. dllEntry is the public routine/function exported by vcgsoap2.dll if ((lpfndllTemplate= (PFNDLL)GetProcAddress(hLibrary,TEXT("dllEntry"))) == NULL) return(ER_ERROR); // Call the dll and pass values to DLL lpfndllTemplate(lpBhvrCom,lpVoid, lpDS); /************************************************************************ * Function Clean Up ************************************************************************/ FreeLibrary(hLibrary); return (ER_SUCCESS); } 6 4. Generate gSOAP web service proxy and XML serialization source code First, download gSOAP toolkit from http://www.genivia.com/Products/downloads.html and unzip it to a local directory Open command prompt and navigate to <gSOAP home dir>\gsoap\bin\win32 and issue the command below: wsdl2h -o calc.h <the WSDL address you saved during ws development> Issue another command: soapcpp2 –I<gSOAP home directory>\gsoap\import> calc.h The above command will generate .h and .cpp files for gSOAP web service proxy and XML serialization routines in source-code format. The files are inside <gSOAP home dir>\gsoap\bin\win32 7 5. Develop gSOAP web client DLL - Create new project and configuration In VC++, create a MFC AppWizard(dll) project and choose Choose Regular DLL with MFC statically linked. Click Finish. Open the Settings dialog under the 'Project' drop down menu. Select the 'Link' tab and locate the Object/library Modules field. And copy and paste the text below right into the dialog jdel.lib jdbodbc.lib jdekrnl.lib jdesetup.lib jdeuser.lib jdegbr.lib jdeoblib.lib jdedia.lib jdedia1.lib jdemail.lib envtool.lib browser.lib jdepkgbld.lib 8 Now go Tools Menu->Options and locate Directories tab. Enter the JDE directories existed on your computer to 'include' files, 'source' files, and 'libraries' as below: 9 - Include gSOAP’s source files into project Need to include into project the generated gSOAP source files below: soapC.cpp soapH.h soapClient.cpp soapStub.h *Soap.nsmap Soap*Proxy.h stdsoap2.h (This file is in <gSOAP home directory>\gsoap\import>) stdsoap2.cpp (This file is in <gSOAP home directory>\gsoap\import>) 10 Again go Project Setting, set the no precompiler header for the CPP files included before. - Edit the main CPP file to call the web service Now let’s edit the DLL’s main CPP file generated by VC++. For my case, it will be vcgsoap2.cpp. Please see the code on page 12 & 13. 11 // vcgsoap2.cpp : Defines the initialization routines for the DLL. // #include "stdafx.h" #include "vcgsoap2.h" //Include JDE file and BSFN .h file which contain the DSTR data structure passed in #include <jde.h> #include <b55gsoap.h> //Include gSOAP proxy .h file and namespace file generared by gSOAP toolkit #include "soapCalc1WSSoapHttpProxy.h" #include "Calc1WSSoapHttp.nsmap" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CVcgsoap2App BEGIN_MESSAGE_MAP(CVcgsoap2App, CWinApp) //{{AFX_MSG_MAP(CVcgsoap2App) // NOTE - the ClassWizard will add and remove mapping macros here. // DO NOT EDIT what you see in these blocks of generated code! //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CVcgsoap2App construction CVcgsoap2App::CVcgsoap2App() { // TODO: add construction code here, // Place all significant initialization in InitInstance } ///////////////////////////////////////////////////////////////////////////// // The one and only CVcgsoap2App object CVcgsoap2App theApp; 12 //export function dllEntry to public extern "C" __declspec(dllexport) int dllEntry (LPBHVRCOM lpBhvrCom, LPVOID lpVoid, LPDSD55GSOAPB2 lpDS) { //Convert JDE MathNumeric type to long type long num1, num2, num3; MathNumericToLong(&lpDS->mnNumber1, &num1); MathNumericToLong(&lpDS->mnNumber2, &num2); //Initalize proxy class object Calc1WSSoapHttp calcws; //Initialize complex-typed parameters and response objects ns1__addNumbers *addNumbers; size_t *addNumbersSize = new size_t; *addNumbersSize = sizeof(ns1__addNumbers); addNumbers = (ns1__addNumbers*) soap_instantiate(calcws.soap,SOAP_TYPE_ns1__addNumbers,"","",addNumbersSize); addNumbers->num1 = num1; addNumbers->double_USCORE2 = num2; ns1__addNumbersResponse *addNumbersResponse; size_t *addNumbersResponseSize = new size_t; *addNumbersResponseSize = sizeof(ns1__addNumbersResponse); addNumbersResponse = (ns1__addNumbersResponse*) soap_instantiate(calcws.soap,SOAP_TYPE_ns1__addNumbersResponse,"","",addNumbersResponseSize); //Call web service method calcws.__ns1__addNumbers(addNumbers,addNumbersResponse); //Retrieve return from response object num3 = addNumbersResponse->return_; //Convert return value to MathNumeric type LongToMathNumeric(num3, &lpDS->mnNumber3); return (TRUE); } 13 Lastly, compile and build the DLL file. 6. Deployment Following general OneWorld procedure to deploy JDE APPL and BSFN. After that, copy the DLL file generated during the previous step into Enterprise Server’s <JDE home directory>\ddp\B7334\system\bin32 directory. Now, use it however you wish. Appendix To understand the solution further, you are advised to read the following as reference: 1. CurrencyConvertor: How to Use gSOAP and Webservices, Part One by Dr.Luiji http://www.codeproject.com/KB/webservices/CurrencyConvertor.aspx 2. Custom DLLs http://www.ocode.net/dlls.html by Darren Ricciardi (Don’t change Struct member alignment from 8 bits to 1 bits and be aware of __stdcall and __cdecl calling convention if you are developing DLL for Enterprise Server instead of fat client) 3. How to use JDeveloper to create and deploy a Java web service3 by Oracle http://www.oracle.com/technology/obe/obe1013jdev/10131/devdepandmanagingws/devdepan dmanagingws.htm License This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL) 14