Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 4 of 4
With NT's regsvr32 utility, SampleAppMessages.dll can register and deregister the SampleApp as the event source with the Event Log. The regsvr32 utility is invoked as regsvr32 SampleAppMessages.dll for registering the SampleApp with the Event Log. regsvr32 -u SampleAppMessages.dll is executed to deregister the SampleApp from the Event Log. The SampleAppMessages.dll exports two functions, DllRegisterServer() and DllUnregisterServer(), that register and deregister the DLL with the Event Log using Window APIs such as RegCreateKey and RegSetValueEx.
The DllRegisterServer() creates a registry key SYSTEM\CurrentControlSet\Services\EventLog\Application\SampleApp. It sets the value for EventMessageFile and CategoryMessageFile as the full directory path for SampleAppMessages.dll. It sets the value of CategoryCount to "2" to reflect the number of categories defined in SampleAppMessages.mc. It also sets TypesSupported as EVENTLOG_ERROR_TYPE, EVENTLOG_WARNING_TYPE, or EVENTLOG_INFORMATION_TYPE out of the event types supported by the Event Log. DllUnregisterServer() deletes the SYSTEM\CurrentControlSet\Services\EventLog\Application\SampleApp to deregister the SampleApp from the Event Log.
JNIEventLog.dll, a Windows DLL created in Visual C++, acts as a JNI DLL, which the SampleApp Java program loads for logging events. The JNIEventLog.dll implements a JNI method, described below, that logs events into the Event Log.
The native method in SampleApp.java is:
private native void logMessage(String message,
int eventID,
int eventSeverity,
int eventCategory);
The function logMessage() possesses these parameters:
message: replaces the placeholder in the message string described for the event in the message file
eventID: the event identifier defined in the message file
eventSeverity: the bitmask of the supported event types
eventCategory: the category ID to which the event belongs; also defined in the message file
After compiling the SampleApp Java application, run the javah utility on SampleApp.class as:
javah -jni SampleApp.class
javah reads the classfile, and, for each native method declaration, it generates the function prototype in a C or C++ header file.
javah's output is a SampleApp.h file with the following declarations:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class SampleApp */
#ifndef _Included_SampleApp
#define _Included_SampleApp
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: SampleApp
* Method: logMessage
* Signature: (Ljava/lang/String;III)V
*/
JNIEXPORT void JNICALL Java_SampleApp_logMessage
(JNIEnv *, jobject, jstring, jint, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
Here, the JNIEnv parameter acts as a hook allowing callback into the JVM. The jobject parameter is the reference to the object that called the native method.
The Visual C++ project JNIEventLog, which includes the SampleApp.h generated by javah, implements the Java_SampleApp_logMessage() JNI method:
JNIEXPORT void JNICALL Java_SampleApp_logMessage
JNIEnv *env,
jobject obj,
jstring message,
jint eventID,
jint eventSeverity,
jint eventCategory)
{
const char *msg = env->GetStringUTFChars(message,0);
WORD wEventID = (DWORD)eventID;
WORD wEventSeverity = (WORD)eventSeverity;
WORD wEventCategory = (WORD)eventCategory;
//Get the handle to the event source 'SampleApp'
HANDLE h = RegisterEventSource(NULL, L"SampleApp");
if(h != NULL){
//convert jstring inot WCHAR
WCHAR *szMsg[1];
zMsg[0] = (WCHAR *)malloc( 2 * strlen(msg) + 2);
for(unsigned int i = 0; i < strlen(msg); i++) {
szMsg[0][i] = (WCHAR)msg[i];
}
szMsg[0][strlen(msg)] = L'\0';
//Log the event in the Event Log
ReportEvent(h,
wEventSeverity,
wEventCategory,
wEventID,
NULL,
1,
0,
(LPCWSTR *)szMsg,
NULL);
DeregisterEventSource(h);
free(szMsg[0]);
}
env->ReleaseStringUTFChars(message, msg);
}
The code obtains the message string's handle by calling the JNI API GetStringUTFChars and converting it into a wchar string. To retrieve the SampleApp's handle (already registered as an event source with the NT Event Log employing SampleAppMessages.dll), call RegisterEventSource. Using that event source handle, call the ReportEvent Windows API to report the event along with the information passed from the Java program. Then deregister the event source.
You must release the memory by calling the JNI API ReleaseStringUTFChars; otherwise, you'll encounter memory leaks in the program.
To build the JNIEventLog.dll, you'll need to add the following to your directories path:
<JAVA_HOME>\jdk1.1.8\include, <JAVA_HOME>\jdk1.1.8\include\win32
You should also add the following to your libraries:
<JAVA_HOME>\jdk1.1.8\lib
The SampleApp Java application demonstrates event logging into the Event Log. It employs the native method logMessage() from the JNIEventLog.dll for logging events into the Event Log. SampleApp comprises two Java classes:
SampleAppEventLogIdsThe sample application's main class, SampleApp, performing typical database operations, inserts and reads employee records. It logs the SQL statements into the Event Log,
as well as any exceptions.
SampleApp contains this JNI method declaration, which logs the events into the Event Log:
private native void logMessage(String message,
int eventID,
int eventSeverity,
int eventCategory);
The SampleApp class loads the JNI DLL on startup through the following code:
static{ System.loadLibrary("JNIEventLog"); }
The SampleApp application inserts an employee record in the writeData() method. The method writeData() logs the SQL statement with SQLSTMT as the event ID, EVENTLOG_INFORMATION_TYPE as the severity, and CAT_DATA_WRITE as the category. Figure 3 shows the output.

Figure 3. SampleApp event message
And here's the code:
String query = "Insert Into employee (emp_id,name) Values("+
empID+",'"+empName+"')";
//Log the data write query in Windows event Log for future //reference
logMessage(query,
EventLogIds.SQLSTMT,
EventLogIds.EVENTLOG_INFORMATION_TYPE,
EventLogIds.CAT_DATA_WRITE);
After inserting the employee record, the readData() method reads the inserted employee record. At the same time, the program logs the Select SQL statement, but with the CAT_DATA_READ category. The catch block in the writeData() method logs all exceptions with the category CAT_DATA_WRITE and in readData() with the category CAT_DATA_READ. All exceptions are logged with ERROR as the event ID and EVENTLOG_ERROR_TYPE as the severity.
The sample application's second class, EventLogIds, contains the constants required for logging different event types from the Java program. By keeping such constants in a
class, you can easily maintain them as more and more messages and categories are added with time. Here's the code:
public class EventLogIds{
//Severities for Windows Event Log
public static final int EVENTLOG_ERROR_TYPE = 1;
public static final int EVENTLOG_WARNING_TYPE = 2;
public static final int EVENTLOG_INFORMATION_TYPE = 4;
//Category IDs defined for the application
public static final int CAT_DATA_READ = 1;
public static final int CAT_DATA_WRITE = 2;
//Event IDs defined for the application
public static final int SQLSTMT = 0x00001000;
public static final int ERROR = 0x00001001;
}
The various event severities possibly used in SampleApp for reporting events are defined exactly in accordance with the Windows API documentation. This way, the Java application is well protected from any change in the values of event severities, as only this class would need to be changed.
You'll also find the categories and messages, along with their identifiers, defined in the SampleAppMessages.mc file.
In Windows NT environments, Java servers must output events in the NT Event Log. By reading such Event Logs, support staff can troubleshoot the conditions that caused errors and determine the context in which those errors occurred. As we've seen, however, the JDK does not provide direct support for writing events to the NT Event Log. But you can write events to the Event Log by using JNI with a C method.
After reading this article, you should understand the NT event logging mechanism, and know how to create sample message files and embed them in the self-registering DLL, how to create a JNI method in C to log events to NT Event Log, and, lastly, how to use a JNI method in a sample Java program. Happy logging!
Read more about Tools & Methods in JavaWorld's Tools & Methods section.