Saturday, April 18, 2015

OpenLink Findur OpenComponents External Plugin

At work we've been trying for the last 2 years to replace our current system with OpenLink Findur. I was involved in integrating our internal pricing library by using their OpenComponents .NET API. It was tough but we successfully delivered that part of the project, so I was out of the project and had been doing other things since then. Around a month ago, I was suddenly asked to take over yet another part of this massive project from a contractor hired to do this as the management didn't want to extend her contract. So that's how I got sucked into this project again T_T.

The part I was asked to take over is a .NET C# Console Application built using OpenLink OpenComponents .NET API. This plugin is attached to Findur End of Day (EOD) workflow and runs at the very end of the workflow. This plugin extracts some of the EOD results and produces xml's needed by a lot of our legacy tools that we don't have time yet to adjust to communicate with Findur. At least not at this phase of the project.

If you're like me, I find debugging extremely important especially when you're pulled out of whatever you're doing, thrown into a massive project and expected to be up and running after 2 hours handover. Well the bad news was that she said it's impossible to debug the plugin. I asked her how she managed to build something quite big (there're more than 5000 lines of codes) without debugging it. She said she put logging lines almost everywhere, pressed F5 and waited until it either crashed (and then checked the log) or finished executing (and then checked the resulting xml's). My first reaction was: Are you kidding me?!? She also said that this plugin could only work when there's only one Findur session running in the application server as users access Findur via Citrix. At this point I had to pinch myself to check whether I was dreaming. Surely something is wrong when you need an extra application server wholly dedicated to test this plugin. It just sounds absurd.

Okay now that I'm done rambling, let's formulate the problems she mentioned and what I did to somehow make it works.

Problem #1: "You cannot debug this external Findur plugin..."


SEHException - External component has thrown an exception

So first thing I did after having all my development environment set up was putting a random breakpoint in the solution and pressing F5. It ran for a couple of seconds and then it stopped at that breakpoint. Hmmm, I thought she said we couldn't debug it? So I pressed F5 again to resume and bang! it threw a 'SEHException - External component has thrown an exception' in:

   Application app = Application.GetInstance();
Ah so this was what she meant by "You cannot debug this external Findur plugin..."

Next thing I did was going to the guy who's responsible for deploying this plugin to a test environment and asked him whether it had ever worked before and how he'd run it. He said it had worked before. At the end of Findur EOD workflow, there's a process that would trigger this plugin. He even demonstrated that it worked by manually double clicking the .exe file. I went back to my desk and double clicked the .exe file in Visual Studio bin\Debug folder. It ran successfully and produced the expected xml's. So it did seem that the contractor was right, we can't debug this plugin.

Being the person that I am, I didn't give up. To be honest I didn't want to take on a project where I'd need to code blindly and invest my time in writing log entries. Besides I wasn't even sure that log entries would help me with coding the logic of extracting data from Findur simulation results. We're talking about lots and lots of Findur Table class inquiries here. I couldn't find anything about this exception on google, nothing related to Findur, so I tried the next best thing: cleaning the solution. It had done the trick in multiple occasions in the past and I was desperate, so why not? And by "cleaning" I meant manually deleting the output files, not using Visual Studio Clean Solution. It refused to delete vshost.exe file as it's in use, obviously because I had the solution still open. Then I thought, "Wait a minute, vshost.exe is a feature in Visual Studio related to debugging and my current problem is related to debugging. Running it by double clicking the .exe works fine." At this point, I just followed my gut instinct, I closed the solution, deleted the vshost.exe, reopened the solution, recompiled and pressed F5. And then the magic happened, it didn't crash on Application.GetInstance(). Hooray!!


Debug stop working after a couple of step-into's

Apparently it's not over yet. Debugging only lasted for approximately 3 step-into's and then it simply refused to stop on any more breakpoint. The yellow line highlighting the current line went away, but it never reached the next line. The solution window title showed "(Running)" and I couldn't do anything but stopped the debugging session and restarted the whole thing. I ended up having to choose my breakpoint very wisely since I only got a limited number of step-into's. Was this what the contractor meant by "You cannot debug this external Findur plugin..."?

Again being the person that I am, I refused to give up. "Choose your breakpoints wisely" lol it even sounds silly. So going back to google search, some people recommended switching off property evaluation and other implicit function calls. This setting can be found in Tools > Options and then select Debuging > General. Find check box Enable property evaluation and other implicit function calls and uncheck it. This, my friends... didn't work.

This worked for me though:
Tools > Import and Export Settings > Reset all settings
If you're reading this because you have the same problem and about to try it out, please please note that you're going to LOSE your Resharper settings (if you're using it) and personalized keyboard shortcuts! So make sure you back up your settings when it asks you to.



Problem #2: "External plugin can only work if there's only one Findur session running..."

Original code:

   Application app = Application.GetInstance();
   Session session = app.Attach();
Application and Session class can be found in Olf.Openrisk.Application namespace. Here we see that we don't tell it to attach to a specific session. No wonder it only worked if there's only one session running. It'll just attach itself to a random session.

Now I want the plugin to attach to a specific Findur database session. If that session is not running, I want the plugin to start it and then attach itself to it. For this purpose, I introduce 3 configuration keys in App.config:

    <add key="DatabaseName" value="Findur_Test" />
    <add key="OlfBinFolder" value="C:\OpenLink\Findur_V14_1_01172015MR_02182015_1037\bin" />
    <add key="OlfParams" value="-olfcfg \\servername\ConfigFiles\TestConfig.olf -u svcAccUser -p 1234567" />
DatabaseName is the name of Findur database session we want to attach our plugin to. OlfBinFolder specifies the location where Findur is installed. There should be an executable master.exe in this bin folder which is the one we use to start Findur. OlfParams specifies the command parameters of master.exe. When you run Findur from the command prompt it reads as follows:
  C:\OpenLink\Findur_V14_1_01172015MR_02182015_1037\bin\master.exe -olfcfg \\servername\ConfigFiles\TestConfig.olf -u svcAccUser -p 1234567

Findur Application class has another Attach method where we can specify a session ID we want to attach to. There can only be one Application instance (because it's a singleton), while we can have multiple Findur sessions running on it.

If we have a Findur session running, we can see the session ID by clicking on the i (information) icon. Unfortunately this session ID changes every time we start a session and there's no way the plugin can access this information without first attaching itself to a running session, so we cannot know beforehand what the session ID is (classic chicken and egg problem isn't it? ;)). Fortunately there's SessionDescriptions property on the Application class which returns all the session ID's running on it. We can iterate through each of these session ID's, attach our plugin to it so that we can ask for the session's database name. When the attached database name is not equal to the database name we want ie. the one we specified in App.config, we detach it and continue with the next session ID and repeat the process until we find the database we want. If we don't find it, return null. Null means that the session we want to attach to is not running and therefore we will start it by running whatever specified in OlfBinFolder and OlfParams.

The adjusted code:

        Application app = Application.GetInstance();
        Session session = GetSession(app);
where:
        private Session GetSession(Application app)
        {     
            string databaseName = ConfigurationManager.AppSettings["DatabaseName"];
            Session session = GetRunningSession(app, databaseName);
            if (session == null)
            {
                string binDir = ConfigurationManager.AppSettings["OlfBinFolder"];
                string parameters = ConfigurationManager.AppSettings["OlfParams"];
                session = app.StartSession(binDir, parameters);
            }

            return session;
        }

        private Session GetRunningSession(Application app, string databaseName)
        {
            IEnumerable<int> sessionIds = app.SessionDescriptions.Select(x => x.Id);
            foreach (int sessionId in sessionIds)
            {
                Session attachedSession = app.Attach(sessionId);
                string attachedDatabaseName = attachedSession.DatabaseName;
                if (attachedDatabaseName != databaseName)
                {
                    app.Detach();
                }
                else
                {
                    return attachedSession;
                }
            }

            return null;
        }

So what is the moral of the story?
* Don't blindly trust what you're told, what does the code say?
* Don't give up and google is your friend ;)

4 comments:

  1. Replies
    1. This comment has been removed by the author.

      Delete
  2. Is there any documents to go through for Openlink Endur open components with .Net

    ReplyDelete
  3. You can download it from OpenLink client portal.

    ReplyDelete