0

I'm working on a Spring MVC project that uses the Sigar library which relies on a DLL file being loaded by Tomcat. When i first start netbeans and press play (when the server is stopped) it compiles fine and the site interacts with the library perfectly. If i close the webpage and hit play again without first restarting Tomcat, it tries to load the library again and crashes during deployment. It looks like Tomcat tries to load the Sigar DLL a second time and crashes while deploying (since i have a Sigar instance as a global variable within a Spring controller. Is there a way for netbeans to automatically restart Tomcat when pressing play?

EDIT

Ok so I am trying to work around this problem by getting Tomcat to only load the DLL if it's not already loaded. I have searched a bit and found that a class like this one should run before the web app you're compiling runs :

@WebListener
public class MDHISServletContextListener implements ServletContextListener
{
    @Override
    public void contextInitialized(ServletContextEvent arg0) 
    {
        loadNativeLibraries();
    }

    private void loadNativeLibraries()
    {
        boolean sigarLoaded = false;

        try
        {
            List<String> nativeLibraries = new NativeLibraryBrowser().getLoadedLibraries();
            for (String library : nativeLibraries)
            {
                if (library.contains("sigar"))
                {
                    sigarLoaded = true;
                    break;
                }
            }

            if (!sigarLoaded)
            {
            System.loadLibrary("C:\\path\\to\\dll\\folder\\sigar-amd64-winnt.dll");
            }
        }
        catch (Exception ex)
        {}
    }
}

I have built the NativeLibraryBrowser class like provided in a post i found and it does indeed return a list of String containing the path to the Sigar DLL when i drop it in Tomcat's bin folder for it to be loaded. However, when i put a breakpoint in this class it is never reached and my web app fails to deploy due to the controller depending on it not being able to initialize. What am i doing wrong?

BIG UPDATE

I was able to dynamically load the library by adding the path to where i put the DLL file to the PATH environment variable and doing :

System.loadLibrary("sigar-amd64-winnt");

The problem is that it ONLY works when my Sigar instance is not global to the controller and i need it to be. It looks like tomcat is instantiating the servlets before a class annotated with WebListener runs. Is there any way to get a library loaded into Tomcat before the servlets are loaded aside from just dropping it in Tomcat's bin folder which brings me back to having to constantly restart it before compiling my app?

Thanks!

Martin
  • 1,977
  • 5
  • 30
  • 67
  • In output window, tomcat output tab (not tomcat log) there is a "fast forward" button wich always restart the server. If that is not enough, you may get what you need customizing the ant run task in build-impl.xml. – ronchi82 Jan 23 '18 at 23:04
  • i had not seen this button, thanks that will definitely be useful. – Martin Jan 24 '18 at 00:10

2 Answers2

0

If you're using maven or something like that to deploy your system you can use a customized phase that stops and re-launches the tomcat server each time you deploy the code.

It's normal that your system crashes, as when you hit the play button again you're trying to re-launch the tomcat server with the same parameters on the same port, usually the 8080 one. If you don't stop the server, maybe manually or maybe with the maven customized phases, you'll get an error, not on deploying the dll that you need, but deploying the tomcat server itself, as netbeans continues on running the server if you don't stop it. If you try to open the tab again you'll see that is still deployed.

In other IDE's, like IntelliJ, there is a special button that allows you to stop and re-run your project from one button but, in my opinion, i think that the maven option is better, as it allows you to take care of the java dependencys very well.

Hope it helped, at least a bit.

  • Unfortunately i've been working on this project on and off for over a year and back then i did not know about Maven. I am however looking into "converting" it to a Maven project in the near future. The redeploying worked fine before i added the Sigar library that loads the DLL, it used port 8080 every time i hit play but somehow it compiled and worked fine every time even without restarting Tomcat. – Martin Jan 24 '18 at 00:08
  • When i initially added Sigar i was not using a global variable on a controller class but rather a local variable to the method inside the controller so the website would compile and be fully usable until you landed on this page and went through this method. Now that the variable is global, hitting play for the second time without restarting Tomcat completely crashes the deployment and the website is not functional at all since Spring / Tomcat fails to pre-initialize the controller class. – Martin Jan 24 '18 at 00:14
  • when you were using your project without Sigar what you were doing was, not restarting tomcat, but re-deploy your project on the same server. But as that loads at the very first with the server deployment the second deploy of the server crashes, as it detects an already existing dll on the running tomcat. Did you tried on make a lookup on the server in order to load the dll only in the case that is not already deployed? That sould make your code to only deploy the dll on the first run, and not every time, which sould solve your problem. – Reyeselda95 Jan 24 '18 at 00:26
  • How can you achieve that? I know you can load a DLL programmatically using System.loadLibrary() without having to put the DLL in Tomcat's bin folder but i'm not sure how to check if it's already been loaded and where i would put such code inside my MVC application (all annotation driven btw) to achieve this. If you can enlighten me on this that would indeed avoid the need to restart Tomcat in the first place since it wouldn't try to load an already loaded library when re-deploying without restarting the server. – Martin Jan 24 '18 at 01:16
  • OK i did find how to check for loaded libraries in this post : https://stackoverflow.com/questions/1007861/how-do-i-get-a-list-of-jni-libraries-which-are-loaded/1008631#1008631 Now where do i put the code that checks if the Sigar DLL is loaded and only loads it if it's not? – Martin Jan 24 '18 at 01:31
  • You should put it before the declaration. I imagine that you load the dll when you create the class instantiation so, in the constructor of the class, instead of putting the dll as an already initializated variable, you check if it's already deployed. If then, you load it from the deployed one in the server and then use it, if not, you deploy it and then use it. Tell me if that worked for you. – Reyeselda95 Jan 24 '18 at 12:22
  • this is a Spring MVC project, i have no control over the instantiation of the controllers (servlets) as far as i know. As i wrote in my last update, my custom ServletContextListener does correctly load the DLL and everything is functional provided that the Sigar instance is not global to a controller. If that is the case, Spring wants to instantiate the controller class before any of this code runs and fails to do so since the DLL is not yet loaded. I am looking for a way to get code to run before Spring instantiates its controllers / repositories / services / beans / etc. Thanks! – Martin Jan 24 '18 at 12:35
  • Ok, if that didn't worked the only solution i can think of is that of the maven one that i told you before, as it stops and re-run the server. Maven is a really easy tool to use and is really nice when it comes to solve dependence issues. I hope you could get your problem solved asap. Good luck :) – Reyeselda95 Jan 24 '18 at 12:54
  • Thank you! I am definitely looking to convert this project to a Maven project. What i am building is really 2 apps : a web app and a backend service. The backend service already uses Maven and i love it! The web app has hundreds of source files and i know it's going to be hell to convert it to Maven but i know i will eventually venture into doing this. Check the answer i posted, it's a cheap hack but it does exactly what i want! Cheers! – Martin Jan 24 '18 at 12:58
0

Well, i found a cheap hack that works. I declared my Sigar instance globally in the controller but i only initialize it when the page is loaded. This solves all my issues but i would still like to know if there is a way to get code to run before Spring instantiates the controllers. Thanks!

Martin
  • 1,977
  • 5
  • 30
  • 67
  • Actually i found that the issue is still happening if i compile my project twice without restarting, even though my code only loads the library if it's not already loaded and even if the DLL file is not present anywhere aside from where i'm telling my code to load it. Since this is an issue that will never happen in a production environment, i'll just have to deal with it i guess. – Martin Jan 24 '18 at 14:54