Detailed Steps To Build the Solution Stack: Build Steps 1-3
Continuing the odyssey of configuring a stack to invoke a privileged DLL from a web page, this installment starts with the signing requirements for the .NET assembly that is your invocation target. Then I cover creating the Applet, a test HTML page, and preparing for creating the JNI DLL that forms the bridge from Applet to native code.
- Create your functional .NET DLL (assembly) – or sign your existing .NET DLL. For the purposes of this example, assume an assembly named: SummaDemo.Client.PrintManager.dll.
- It should be a DLL, not just to avoid the lack of control of having an out-of-process application triggered by your web page. If you do ALSO need an EXE to include the same capabilities – I recommend that you create one that references this assembly for the shared functionality.
- This DLL must be signed.
- For an existing DLL that you cannot modify, you can sign from the command line using the SignTool.exe (http://msdn.microsoft.com/en-us/library/8s9b9yaz.aspx#sign). Just remember the caveat from above; that signed (strong-named) assemblies can only use types from other strong-named assemblies. Depending on your dependencies (sic), you may have to sign “all the way down.” (http://en.wikipedia.org/wiki/Turtles_all_the_way_down)
- For a new DLL, just set the information on the signing tab of the project properties.
- Create an Applet in Eclipse, and package it in a jar file, for example: PrintApplet.jar.
- The Applet should have:
- A public declaration for one or more JNI functions defining the interface to the next layer. No code for the function is needed, just the declaration. When that Applet function is invoked, it will invoke the JNI function of the corresponding name:
public native void jnifunctionname(argtype argname, …);
e.g.public native void invokePrintManager(int type, String encodedData);
- The project should have a manifest file MANIFEST.MF containing:
Manifest-Version: 1.0
Trusted-Library: true
- Code to set the java library path to include the location of your JNI DLL and the .netmodule. This requires planning as to where you will install them on the client. The following is an example of code to ensure the JNI library is loaded:
<code>String libPath = System.getenv("ProgramFiles(x86)") + "\\" + installDirectory; File jniFile = new File(libPath + "\\PrintJNI.dll"); File netModuleFile = new File(libPath + "\\PrintModule.netmodule"); System.setProperty("java.library.path", libPath); Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths"); fieldSysPath.setAccessible(true); fieldSysPath.set(null, null); System.loadLibrary("PrintJNI");</code>
- A public declaration for one or more JNI functions defining the interface to the next layer. No code for the function is needed, just the declaration. When that Applet function is invoked, it will invoke the JNI function of the corresponding name:
- The Applet should have:
- Create a test html page for testing the solution
- Prior to creating an installer, the solution can be tested by putting all binaries in the folder where the jar file resides and is referenced by the html <object> tag.
- Here is sample code for an html test page:
<code><html> <head> <script language="javascript"> function appletCallPrivilegedCode() { myApplet = document.getElementById("PrintApplet"); // alert('Before calling') myApplet.invokePrintManager(1, "Applet arg passed from javascript.") //alert('After calling') } </script> </head> <body> <object name="PrintApplet" id="PrintApplet" type="application/x-java-applet" height="120" width="120"> <param name="code" value="PrintApplet.class" /> <param name="archive" value="file:../PrintApplet.jar" /> Applet failed to run. No Java plug-in was found. </object><br> <INPUT TYPE="button" NAME="bPrint" VALUE="Click for Printing" onClick="appletCallPrivilegedCode();" ><br> <body> </html></code>
- Create the jar file
- Right-click on the root of the Package Explorer in Eclipse.
- Select Export
- Under Java, select JAR File.
- In the “Select resources to export:” tree on the left side, under src, deselect everything except the (default package). Nothing should be selected in the list on the right. Underneath the resources tree check only “Export generated class files and resources.”
- Sign the jar file using keytool (http://docs.oracle.com/javase/7 /docs/technotes/tools/windows/keytool.html) and jarsigner (http://docs.oracle.com/javase/7/docs/technotes/tools/windows/jarsigner.html)
- For a temporary development signing, simply:
- Open a Command Prompt
- Change to the location of the jar file.
- Create a keystore if you don’t have one already defined, the final argument after the keystore is the keystore alias.
> keytool –selfcert -genkeypair -keystore MyKeystore –alias PrintManager
- you will be prompted for LDAP info: First & Last Name, Org Unit (e.g. Dev), Organization, City, State, two-letter country code
- To sign, execute the following command-line
> jarsigner –keystore MyKeystore PrintApplet.jar PrintManager
- Enter the password when prompted.
- The last arg is the keystore alias - in this case: "PrintManager"
- For a production deployment, sign with a keystore located at a URL accessible to your client browsers.
- For a temporary development signing, simply:
- Use javah to generate the JNI.h file:
> javah –jni fully_qualified_class_name
- The javah command (http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javah.html) is run in the folder where the class file is, or you can have the class file on the classpath, or you can specify the classpath with a javah arg. The output .h file is named with –o, or you can let it default and rename it later.
- If you are having problems with "could not find class file" or "not a valid class name" errors when running javah, navigate to the folder that contains the javah.jar and tools.jar (Program Files/Java/...). Then run
> javah -classpath …\path_to_PrintApplet\src –jni PrintApplet
Next Up... All the Myriad Technical Details (conclusion)
The final installment will cover the remaining components in the stack and wrap it all up:
- Signing and settings for the JNI DLL, and the .netmodule, and putting it all together