How does the java Oengineserver/NETOI talk to an OpenEngine? (OpenInsight 32-bit)
At 30 DEC 2021 02:14:58AM Joshua Goddard wrote:
Could someone please explain how the java OEnginerServer/NETOI talks to an OpenEngine?
At 30 DEC 2021 03:16AM Andrew McAuley wrote:
Assuming I am understanding the question correctly, when OI 1 was launched it was intended to be middleware, allowing any external program to communicate via the engine to allow access to any database. To this end it introduced something called REVCAPI. There's some limited documentation here. Checkout also REVCAPI_EQUATES in the online help.
World leaders in all things RevSoft
At 30 DEC 2021 09:22AM bob carten wrote:
Here are some simple examples of using revCapi to talk to an oengine.
These correlate to the Oengine documentation referenced by Sprezz.
C#
using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Collections.Specialized; using System.Threading; using System.Text; using System.IO; namespace ghIPSS_Console { class RevCapiWrapper /// <summary> /// Summary description for RevCapiWrapper. /// This Class is an interop wrapper for RevCap32.dll /// /// 24 March 2005 rjc Created /// </summary> { // Function Prototypes for RevCapi [ DllImport("REVCAP32.DLL")] protected internal static extern int RevInitializeApi(); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevTerminateApi(); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevGetApiError(); // The old way to start the engine and open a queue [ DllImport("REVCAP32.DLL")] protected internal static extern int RevStartLocalEngine(String Pathname, String Database); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevShutdownLocalEngine(byte bSuppressMsg); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevOpenQ(String Qname, String UserName, String Password, out int Queue) ; [ DllImport("REVCAP32.DLL")] protected internal static extern int RevCloseQ(int Queue); // The new way to start an engine and open queues const int REV_CREATE_ENGINE_OPEN_EXISTING = 0 ; const int REV_CREATE_ENGINE_CREATE_NEW = 1; const int REV_CREATE_ENGINE_OPEN_ALWAYS = 2; const int REV_CREATE_ENGINE_INDEXER = 16; const int REV_CREATE_ENGINE_WAIT_ON_CLOSE = 32; const int REV_CREATE_ENGINE_NO_UI = 64; const int UNPROCESSED = 0; // Server has not begun request. const int PROCESSING = 1; // Server is processing request. const int DATA_AVAILABLE = 2; // Server has data available. const int COMPLETED = 3; // Server has completed request, status information is available. const int PROC_ERROR = 4; // Server process failed, status information is available. const int INFO_AVAILABLE = 5; // Server has intermediate status information available. const int INFO_REQUEST = 10 ; // Server is requesting info [ DllImport("REVCAP32.DLL")] protected internal static extern int RevCreateEngine(String Server, String Database, int nFlags, int nShutdownSessions, out int Engine); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevCloseEngine( int Engine ); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevCreateQueue( int hEngine , String pQueueName, String pDatabase, String pUserName, String pPassword, out int Queue ); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevCloseQueue( int Queue ); //The rest of the api is the same [ DllImport("REVCAP32.DLL")] protected internal static extern int RevGetEngine( int Queue, out int Engine) ; [ DllImport("REVCAP32.DLL")] protected internal static extern int RevGetSizeOfQNames(); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevGetQNames(StringBuilder Buffer, long buffSize, char Delimiter) ; [ DllImport("REVCAP32.DLL")] protected internal static extern int RevGetSizeOfQStatus(int Queue); //[ DllImport("REVCAP32.DLL")] //protected internal static extern int // RevGetQStatus( int QUEUE, LPQSTATUS As Object) // ; [ DllImport("REVCAP32.DLL")] protected internal static extern int RevSetScript( String Script, int ScriptSize); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevSetScriptArg(int PlaceNo, String Value, int dwSize); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevSendScript(int QUEUE, int hTransact, out int Request ); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevSendImm(int Queue, String Script, int ScriptLen, int Transact, int Request, StringBuilder Result); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevSend(int Queue, String Script, int ScriptLen, int Priority, int Transact, out int Request); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevSendArg(int Request, int Position, String Value, int ValueLen) ; [ DllImport("REVCAP32.DLL")] protected internal static extern int RevEndSend_ (int Request) ; [ DllImport("REVCAP32.DLL")] protected internal static extern int RevPoll(int Request, out int Status); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevWait(int Request, out int Status); //[ DllImport("REVCAP32.DLL")] //protected internal static extern int // RevWaitEx( int Request, DWORD, DWORD, UINT, UINT, LPINT) ; [ DllImport("REVCAP32.DLL")] protected internal static extern int RevEndRequest(int Request); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevGetSizeOfRow( int Request); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevGetValueOfRow( int Request, StringBuilder Buffer, int BuffSize); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevGetNumberOfColumns(int Request); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevGetDataTypeOfColumn(int Request, int ColumnNr); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevGetSizeOfColumn(int Request, int ColumnNr); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevGetValueOfColumn(int Request, int ColNo, StringBuilder Buffer, int BuffSize); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevGetSizeOfStatusText(int Request); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevGetStatusText(int Request, StringBuilder buffer, int bufferSize, char delimiter); [ DllImport("REVCAP32.DLL")] protected internal static extern int RevRespond(int Request, StringBuilder Buffer, int BufferSize); // // * End function prototypes * // // Fields private static int m_instanceCount = 0; // Setting Names const string WORKING_DIRECTORY = "WorkingDirectory"; const string OESERVER_NAME = "ServerName"; const string DATABASE_NAME = "DatabaseName"; const string CREATE_FLAGS = "CreateFlags"; const string SHUTDOWN_SESSIONS = "ShutdownSessions"; const string QUEUE_NAME = "QueueName"; const string USER_NAME = "UserName"; const string USER_PASSWORD = "UserPassword"; const string PROCEDURE_NAME = "ProcedureName"; // Default values const string DEFAULT_PROCEDURE_NAME = "RUN_MY_REQUEST"; const string DEFAULT_ENGINE_SECTION = "DefaultEngine"; // Mv Delimiters const char RM = '\u00FF'; const char FM = '\u00FE'; const char VM = '\u00FD'; // Engine Settings // The intent is to let you set a section to determine which engine to run //private static string m_server = ""; private static string m_database = "MYAPP"; private static string m_username = "MYUSER"; private static string m_password = "MYPASSWORD"; private static string m_workingdirectory = "c:\\revsoft\\OINSIGHT"; //private static string m_queue_name = ""; private static int m_create_flags = 1; private static int m_shutdownsessions = 1; private static string m_procedure_name = DEFAULT_PROCEDURE_NAME; //private static int m_engine = 0; //private static int m_queue = 0; //private static string m_rowDelim = "\r\n"; private string response = ""; // * end fields * public RevCapiWrapper() { // Default Section //m_iniSection = DEFAULT_ENGINE_SECTION; Initialise(); } public RevCapiWrapper( string SectionName) { // Pass in Section //m_iniSection = "DefaultEngine"; Initialise(); } private void Initialise() { // Get Session Parameters from Ini File string strTest; /* * m_workingdirectory = oIniFile.IniReadValue(m_iniSection, WORKING_DIRECTORY); * m_server = oIniFile.IniReadValue(m_iniSection, OESERVER_NAME); * m_database = oIniFile.IniReadValue(m_iniSection, DATABASE_NAME); * m_username = oIniFile.IniReadValue(m_iniSection, USER_NAME); * m_password = oIniFile.IniReadValue(m_iniSection, USER_PASSWORD); */ //strTest = oIniFile.IniReadValue(m_iniSection, CREATE_FLAGS) ; strTest = "1"; switch ( strTest) { case "0" : m_create_flags = 2; break; case "1" : m_create_flags = 1; break; case "2" : m_create_flags = 2; break; case "64" : m_create_flags = 64; break; case "65" : m_create_flags = 65; break; default: m_create_flags = 1; break; } //strTest = oIniFile.IniReadValue(m_iniSection, SHUTDOWN_SESSIONS) ; strTest = "1"; switch ( strTest) { case "0" : m_shutdownsessions = 2; break; case "1" : m_shutdownsessions = 1; break; default: m_shutdownsessions = 1; break; } //strTest = oIniFile.IniReadValue(m_iniSection, PROCEDURE_NAME) ; strTest = "TEST_ISO8583_MANAGER"; if ( strTest != "" ) { m_procedure_name = strTest; } else { m_procedure_name = DEFAULT_PROCEDURE_NAME; } // Init Api for the first engine if ( m_instanceCount == 0 ) { Environment.CurrentDirectory = m_workingdirectory; RevInitializeApi(); } } ~RevCapiWrapper() { this.Close(); } public void Close() { //if ( m_queue != 0 ) //{ // RevCloseQueue( m_queue ) ; // m_queue = 0; //} //if ( m_engine != 0 ) //{ // RevCloseEngine( m_engine ) ; // m_engine = 0 ; //} // last engine out kills the api //m_instanceCount-- ; //if ( m_instanceCount == 0 ) RevTerminateApi(); } public string Response { get { return response; } } public string RunCommand( string strMethod, string request ) { int lret = 0; bool bOK = true; string encoded = base64Encode(request); response = ""; // bump the engine count m_instanceCount++; // set the engine name // Note: I use the "\\.\pipename" format for the server name // to get an external, i.e. out of process, engine // without this you can only start a single engine string server = "\\\\.\\SK" + m_instanceCount.ToString("00"); string queue_name = "QK" + m_instanceCount.ToString("00"); int queue = 0; int engine = 0; //server="8084"; //m_create_flags = 0; //m_shutdownsessions = 0; // Is there a queue? if (bOK) { try { // Change the current directory. Environment.CurrentDirectory = (m_workingdirectory); lret = RevCreateEngine(server, m_database, m_create_flags, m_shutdownsessions, out engine ) ; if (lret == 0 ) { lret = RevCreateQueue(engine, queue_name, m_database, m_username, m_password, out queue); if (lret != 0 ) { this.Close(); } } } catch ( Exception ex ) { Console.WriteLine(ex.Message); lret = -1; this.Close(); } } string strReturnValue = ""; int myStatus = 0; if ( lret == 0 && bOK) { int rowCount = 0 ; int pollLen = 0; StringBuilder resultBuffer = new StringBuilder(""); StringBuilder pollBuffer; string strFuncName = m_procedure_name; string script = "RUN " + strFuncName + " '" + strMethod + "', " + " '" + encoded + "'"; string statusText = ""; int myRequest = 0; char chDelim = '\t'; try { lret = RevSetScript(script, script.Length); if (lret == 0) { lret = RevSendScript(queue, 0, out myRequest); } if (myRequest != 0) { do { lret = RevPoll(myRequest, out myStatus); switch (myStatus) { case UNPROCESSED: // Server has not begun request. break; case PROCESSING: // Server is processing request. break; case DATA_AVAILABLE: // Server has data available. // add break between rows rowCount++; //if ( rowCount > 1) // resultBuffer.Append( m_rowDelim ); int colCount = RevGetNumberOfColumns(myRequest); int wColNo; string this_val = ""; for (wColNo = 1; wColNo <= colCount; wColNo++) { // Fieldmark between columns if (wColNo > 1) resultBuffer.Append(FM); // Get the data for this columns pollLen = RevGetSizeOfColumn(myRequest, wColNo); if (pollLen > 0) { pollBuffer = new StringBuilder(pollLen); lret = RevGetValueOfColumn(myRequest, 1, pollBuffer, pollLen); this_val = pollBuffer.ToString(); // Append the column resultBuffer.Append(this_val); } } break; case COMPLETED: // Server has completed request, status information is available. // Get the status data pollLen = RevGetSizeOfStatusText(myRequest); if (pollLen > 0) { pollBuffer = new StringBuilder(pollLen); lret = RevGetStatusText(myRequest, pollBuffer, pollLen, chDelim); statusText = pollBuffer.ToString(); resultBuffer.Append(statusText); } break; case PROC_ERROR: // Server process failed, status information is available. // Get the status data pollLen = RevGetSizeOfStatusText(myRequest); if (pollLen > 0) { pollBuffer = new StringBuilder(pollLen); lret = RevGetStatusText(myRequest, pollBuffer, pollLen, chDelim); statusText = pollBuffer.ToString(); resultBuffer.Append(statusText); } break; case INFO_AVAILABLE: // Server has intermediate status information available. pollLen = RevGetSizeOfStatusText(myRequest); if (pollLen > 0) { pollBuffer = new StringBuilder(pollLen); lret = RevGetStatusText(myRequest, pollBuffer, pollLen, chDelim); statusText = pollBuffer.ToString(); resultBuffer.Append(statusText); } break; case INFO_REQUEST: // Server is requesting info resultBuffer.Append(statusText); break; } } while ((myStatus != COMPLETED) && (myStatus != PROC_ERROR)); strReturnValue = resultBuffer.ToString(); } RevEndRequest(myRequest); } catch (Exception e) { strReturnValue = " RunRequest Failed ..."; System.Console.WriteLine("{0} \n {1}", strReturnValue, e.Message); if (myRequest != 0) RevEndRequest(myRequest); } finally { if (queue != 0) { RevCloseQueue(queue); queue = 0; } if (engine != 0) { RevCloseEngine(engine); engine = 0; } //m_instanceCount--; } } return strReturnValue; } public bool runRequest(string OiMethod, string request) { string encoded = base64Encode(request); bool isOk = true; string result = RunCommand(OiMethod, request); if (isOk) { response = base64Decode(result); } return isOk; } public string base64Encode(string data) { try { byte[] encData_byte = new byte[data.Length]; encData_byte = System.Text.Encoding.ASCII.GetBytes(data); string encodedData = Convert.ToBase64String(encData_byte); return encodedData; } catch (Exception e) { throw new Exception("Error in base64Encode" + e.Message); } } public string base64Decode(string data) { try { System.Text.ASCIIEncoding encoder = new System.Text.ASCIIEncoding(); System.Text.Decoder AsciiDecode = encoder.GetDecoder(); byte[] todecode_byte = Convert.FromBase64String(data); int charCount = AsciiDecode.GetCharCount(todecode_byte, 0, todecode_byte.Length); char[] decoded_char = new char[charCount]; AsciiDecode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0); string result = new String(decoded_char); return result; } catch (Exception e) { throw new Exception("Error in base64Decode" + e.Message); } } } }Basic+ example
Function TEST_REVCAPI(method) /* ** Purpose: Test calling revCapi ** ** Usage: ** run TEST_REVCAPI 'SUB' to test callsubroutine ** run TEST_REVCAPI 'FUNC' to test callFunction ** run TEST_REVCAPI '' to test CreateRequest ** * Notes: * rjc 12-07-10 Created */ Declare Function rti_createGuid $Insert revcapi_equates $Insert Msg_Equates If Assigned(method) Else method = '' * Connect to an oinsight serverSpec = "\\.\":rti_createGuid() databasename = @APPID<1> flags = 0 shutdownSessions = 0 username = @username password = @username ;* assume password same as username queueName = '' path = drive() If path[-1,1] = '\' Then path[-1,1] = '' * * revCapi will only start an OENGINE * If don't need to start oi, use startflag = 1 or startflag = 65 for hidden engine * * For this example, I want to use Oi. * That let's you run oipi or windows in the other copy. * So, launch a child OI using a /sn parameter, then connect to it with startflag = 0 * * cmd = "oinsight.exe" params = ' /sn=':serverspec : ' /ap=' : databasename : ' /un=':username : ' /pw=':password: ' /dv=1' Call shellExecute(0, 'Open':\00\, cmd:\00\, params:\00\, Drive():\00\, 0) * * 15 second delay to allow OI to start * elapsed = 0 max_elapsed = 15 loop started = time() Loop Call winyield() While time() = started Repeat elapsed +=1 Call send_Info( 'delay ' : elapsed : ' of ' : max_elapsed : ' seconds') Until elapsed ge max_elapsed Repeat engine = 0 queue = 0 error = 0 returnvalue = '' statustext = '' Error = CreateEngine(Engine, ServerSpec, DatabaseName, Flags, ShutdownSessions) If Not(error) then Error = CreateQueue(Queue, Engine, QueueName, DatabaseName, UserName, Password) End oiFuncName = 'TEST_REVCAPI_SUB' oiParam = databasename Begin Case Case error Case indexc(method, 'Func', 1) Call WinYield() Error = CallFunction(Queue, returnvalue, oiFuncName, oiParam) Call WinYield() Case indexc(method, 'Sub', 1) Call WinYield() Error = CallSubroutine(Queue, oiFuncName, oiParam) Call WinYield() Case 1 script = "RUN " : oiFuncName : " '" : oiParam : "'"; statusText = ""; request = 0; Status = '' statusText = '' returnvalue = '' this_reply = '' Error = CreateRequest(request, Queue, Script, '') if ( request ne 0 ) then loop Error = PollForReply(Request, Status) begin case case Status eq UNPROCESSED$ // Server has not begun request. null case Status eq PROCESSING$ // Server is processing request. null case Status eq DATA_AVAILABLE$ // Server has data available. Error = GetReply(Request, this_reply) returnvalue := this_Reply case Status eq COMPLETED$ // Server has completed request, status information is available. Error = GetStatusText(Request, @vm, StatusText) case Status eq PROC_ERROR$ // Server process failed, status information is available. // Get the status data // Get the status data Error = GetStatusText(Request, @vm, StatusText) case Status eq INFO_AVAILABLE$ // Server has intermediate status information available. this_Text = '' Error = GetStatusText(Request, @vm, this_Text) Call send_dyn(this_text) case Status eq INFO_REQUEST$ // Server is requesting info this_Text = '' Error = GetStatusText(Request, @vm, this_Text) def = '' def<mType$> = 'RC' def<mCaption$> = 'Info Needed' def<mText$> = this_text ans = Msg(@window, def) end case while ( (Status ne COMPLETED$) and ( Status ne PROC_ERROR$) ) repeat CloseRequest(Request) end End case // Clean Up - close queue and engine. Becuase I used 0 for shutdoen sessions it will not close the OI // if queue then x = CloseQueue(Queue) if engine then x = CloseEngine(Engine) Call Send_Dyn(' Response = ' : Quote(returnvalue)) Call Send_Dyn(' Status = ' : Quote(statustext)) Call Send_Dyn(' error = ' : Quote(error)) Return ''Function TEST_REVCAPI_SUB(text) If Assigned(text) Else text = '' ans = 'you sent ' : quote(text) Call Set_Status(1, 'Happy') Return ans
At 30 DEC 2021 06:45PM Joshua Goddard wrote:
Thanks, but my question was more: how does revcapi talk to the OEngnie?
At 31 DEC 2021 09:52AM bob carten wrote:
Are you asking about the transport protocol? RevCapi uses named pipes or tcpip. RCL4. The ServerName parameter determines which protocol to use. The default is named pipe. If you specify a port number then revcapi uses tcpip. If you look at the engineinfo you can see the named pipe name or tcpip port that is being used.
For example
/SN=BOB will open a named pipe "BOB"
/SN= 18123 will connect on tcpip port 18123
At 04 JAN 2022 01:30AM Joshua Goddard wrote:
Thanks, that's what I wanted to know.