When developing J2EE web-applications is generally desired to deploy the entire application in a single WAR file containing all assets and required non-standard resources, such as additional libraries and drivers etc.:

 

 

All of these are 100% implemented in Java and can therefore be deployed within the context (In J2EE a web-application is referred to as Context). JavaMapScript however is a wrapped native library and accessed via JNI (Java Native Interface). In Java native libraries can only be loaded once for a particular JVM instance. Since all contexts within a J2EE container (application server e.g. Tomcat) share the same JVM, attempting to load the same native library from a different context (or even the same context, if that context had been reloaded), would cause the native library to crash, as each context has its own ClassLoader who has no way of knowing that the library has already been loaded by a different context / class loader. To overcome this problem, MapScript must be deployed separately from the context and installed in either the common or shared global context of the server (see Tomcat 5.5 Directory Structure below). Attempting to load a class or library from the shared context will cause it to be loaded through the shared class loader. This alone still not sufficiently resolves this issue.

 

Tomcat 5.5 Directory Structure
CATALINA_HOME
├───bin
├───common
├───conf
├───logs
├───server
├───shared
│   ├───classes (MapScriptLoader.class)
│   ├───lib (mapscript.jar)
│   └───mapscript (*.dll, *.so)
│       ├───fonts (*.ttf)
│       ├───nad
│       └───symbols (*.sym, *.gif, *.png)
├───temp
├───webapps
│   ├───ROOT
│   └───cis (*.jsp, *.jspf, *.css)
│       ├───admin (*.jsp)
│       ├───images (*.gif, *.jpg, *.png)
│       ├───javascript (*.js)
│       ├───layercontrol (*.jsp)
│       ├───map (*.map)
│       ├───META-INF (context.xml)
│       ├───ms_tmp (*.gif)
│       └───WEB-INF (*.xml, *.tld)
│           ├───classes (*.class)
│           └───lib (*.jar)
└───work

 

A separate class is required to load the actual native library. The loadLibrary statement must be either be contained in a singleton pattern or placed in a static block The solution provided by Umberto Nicoletti uses the former, but this example uses a static block instead, as this is easier to use and less error prone, because loading the native library within a static block located in the class definition will automatically ensure that the System.loadLibrary statement is only ever executed once without having to perform addition checks as necessary with a Singleton. Furthermore this method allows loading the library in the same manner most drivers are loaded in Java via Class.forName:

 

public class MapScriptLoader
{
   
static {
     
   try {
     
       System.loadLibrary("mapscript"); //load native library
         System.out.println(" * mapscript native library loaded *");
     
   } catch (Exception e) {
             System.err.println(" * error loading native library *");
 
           System.err.println("Error is: " + e);
             e.printStackTrace();
      
 }
}
}

 

In order for the JVM to successfully load the MapScript library, the mapscript.dll (or mapscript.so under Linux) must be located on the search path. To set the PATH environmental variable during the start-up of Tomcat the bin/setenv.bat (setenv.sh) batch/shell file must contain the following lines (Windows only):

 

SET PATH=%PATH%;%CATALINA_HOME%\shared\mapscript
SET PROJ_LIB=%CATALINA_HOME%\shared\mapscript\nad

 

The PROJ_LIB variable is required by mapscript.dll to locate the directory containing the projections definitions. 

 

This MapScriptLoader class can now be loaded from within any context without crashing the JVM:

try { 
    Class.forName("MapScriptLoader");
} catch(Throwable t) { t.printStackTrace(); }