16 WebLogic JMS C API

Understand the requirements, design principles, security considerations and implementation guidelines need to use the WebLogic JMS C API to create C clients that can access WebLogic JMS applications and resources.

What Is the WebLogic JMS C API?

The WebLogic JMS C API is an application program interface that enables you to create C client applications that can access WebLogic JMS applications and resources.

The C client application then uses the Java Native Interface (JNI), described at http://docs.oracle.com/javase/8/docs/technotes/guides/jni/index.html, to access the client-side Java JMS classes. See Figure 16-1.

For this release, the WebLogic JMS C API adheres to the JMS Version 1.1 specification to promote the porting of Java JMS 1.1 code. See the JMS C API Reference for Oracle WebLogic Server.

Figure 16-1 WebLogic JMS C API Client Application Environment

Description of Figure 16-1 follows
Description of "Figure 16-1 WebLogic JMS C API Client Application Environment"

System Requirements

Understand the system requirements needed to use WebLogic JMS C API in your environment.

  • A list of supported operating systems for the WebLogic JMS C API is available from the Oracle Fusion Middleware Supported System Configurations page. See Supported Configurations at What's New in Oracle WebLogic Server 12.2.1.3.0.

  • A supported JVM for your operating system.

  • An ANSI C compiler for your operating system.

  • One of the following WebLogic clients to connect your C client applications to your JMS applications:

    • The WebLogic application client (wlfullclient.jar file). See Using the WebLogic JarBuilder Tool in Developing Standalone Clients for Oracle WebLogic Server.

    • The WebLogic JMS thin client (wljmsclient.jar file). See the WebLogic JMS Thin Client in Developing Standalone Clients for Oracle WebLogic Server.

Design Principles

Understand the design principles for porting and developing applications for the WebLogic JMS C API.

Java Objects Map to Handles

The WebLogic JMS C API is handle-based to promote modular code implementation. This means that in your application you implement Java objects as handles in C code. The details of how a JMS object is implemented is hidden inside a handle. However, unlike in Java, when you are done with a handle, you must explicitly free it by calling the corresponding Close or Destroy methods. See Memory Allocation and Garbage Collection.

Thread Utilization

The handles returned from the WebLogic JMS C API are as thread—safe as their Java counterparts. For example:

  • javax.jms.Session objects are not thread-safe, and the corresponding WebLogic JMS C API handle, JmsSession, is not thread safe.

  • java.jms.Connection objects are thread-safe, and the corresponding WebLogic JMS C API handle, JmsConnection, is thread safe.

As long as concurrency control is managed by the C client application, all objects returned by the WebLogic JMS C API can be used in any thread.

Exception Handling

Note:

The WebLogic JMS C API uses integer return codes.

Exceptions in the WebLogic JMS C API are local to a thread of execution. The WebLogic JMS C API has the following exception types:

  • JavaThrowable represents the class java.lang.Throwable.

  • JavaException represents the class java.lang.Exception.

  • JmsException represents the class javax.jms.JMSException. All standard subclasses of JMSException are determined by bits in the type descriptor of the exception. The type descriptor is returned with a call to JmsGetLastException.

Type Conversions

When you interoperate between Java code and C code, typically one of the main tasks is converting a C type to a Java type. For example, a short type is a two-byte entity in Java as well as in C. The following type conversions that require special handling:

Integer (int)

Integer (int) converts to JMS32I (4-byte signed value).

Long (long)

Long (long) converts to JMS64I (8-byte signed value).

Character (char)

Character (char) converts to short (2-byte Java character).

String

String converts to JmsString.

Java strings are arrays of 2 -byte characters. In C, strings are generally arrays of 1-byte UTF-8 encoded characters. Pure ASCII strings fit into the UTF-8 specification. For more information about UTF-8 string, see http://www.unicode.org. It is inconvenient for C programmers to translate all strings into the 2-byte Java encoding. The JmsString structure allows C clients to use native strings or Java strings, depending on the requirements of the application.

JmsString supports two kinds of strings:

  • Native C string (CSTRING)

  • JavaString (UNISTRING)

A union of the UNISTRING and CSTRING called uniOrC has a character pointer called string that can be used for a NULL terminated UTF-8 encoded C string. The uniOrC union provides a structure called uniString, which contains a void pointer for the string data and an integer length (bytes).

When the stringType element of JmsString is used as input, you should set it to CSTRING or UNISTRING, depending on the type of string input. The corresponding data field contains the string used as input.

The UNISTRING encoding encodes every 2– bytes as a single Java character. The 2-byte sequence is big-endian. Unicode calls this encoding UTF-16BE (as opposed to UTF-16LE, which is a 2-byte sequence that is little-endian). The CSTRING encoding expects a UTF-8 encoded string.

When the stringType element of JmsString is used as output, the caller has the option to let the API allocate enough space for output using malloc, or you can supply the space and have the system copy the returned string into the provided bytes. If the appropriate field in the union (either string or data) is NULL, then the API allocates enough space for the output using malloc. It is the callers responsibility to free this allocated space using free when the memory is no longer in use. If the appropriate field in the union (string or data) is not NULL, then the allocatedSize field of JmsString must contain the number of bytes available to be written.

If there is not enough space in the string to contain the entire output, then allocatedSize sets to the amount of space needed and the API called returns JMS_NEED_SPACE. The appropriate field in the JmsString (either string or data) contains as much data as could be stored up to the allocatedSize bytes. In this case, the NULL character may or may not have been written at the end of the C string data returned. Example:

For example, to allocate 100 bytes for the string output from a text message, you would set the data pointer and the allocatedSize field to 100. The JmsMessageGetTextMessage API returns JMS_NEED_SPACE with allocatedSize set to 200. Call realloc on the original string to reset the data pointer and call the function again. Now the call succeeds, and you are able to extract the string from the message handle. Alternatively, you can free the original buffer and allocate a new buffer of the correct size.

Memory Allocation and Garbage Collection

All resources that you allocate must also be disposed of it properly. In Java, garbage collection cleans up all objects that are no longer referenced. However, in C, all objects must be explicitly cleaned up. All WebLogic JMS C API handles given to the user must be explicitly destroyed. Notice that some handles have a verb that ends in Close while others end in Destroy. This convention distinguishes between Java objects that have a close method and those that do not. For example:

  • The javax.jms.Session object has a close method so the WebLogic JMS C API has a JmsSessionClose function.

  • The javax.jms.ConnectionFactory object does not have a close method so the WebLogic JMS C API has a JmsConnectionFactoryDestroy function.

    Note:

    A handle that has been closed or destroyed should never be referenced again.

Closing Connections

In Java JMS, closing a connection implicitly closes all subordinate sessions, producers, and consumers. In the WebLogic JMS C API, closing a connection does not close any subordinate sessions, producers, or consumers. After a connection is closed, all subordinate handles are no longer available and need to be explicitly closed.

Helper Functions

The WebLogic JMS C API provides some helper functions that do not exist in WebLogic JMS. These helpers are explained fully in the JMS C API Reference for Oracle WebLogic Server. For example:

JmsMessageGetSubclass operates on a JmsMessage handle and returns an integer corresponding to the subclass of the message. In JMS, this could be accomplished using instanceof.

Security Considerations

The WebLogic JMS C API supports WebLogic compatibility realm security mode based on a username and password.

The username and password must be passed to the initial context in the SECURITY_PRINCIPAL and SECURITY_CREDENTIALS fields of the hash table used to create the InitialContext object.

Implementation Guidelines

Understand the limitations when you implement the WebLogic JMS C API.

  • It does not support WebLogic Server JMS extensions, including XML messages.

  • It does not support JMS Object messages.

  • It creates an error log if an error is detected in the client. This error log is named ULOG.mmddyy (month/day/year). This log file is fully internationalized using the NLSPATH, LOCALE, and LANG environment variables of the client.

  • Users who want to translate the message catalog can use the gencat utility provided on Windows or the gencat utility of the host platform. If the generated catalog file is placed according to the NLSPATH, LOCALE, and LANG variables, then the translated catalog will be used when writing messages to the log file.

  • You can set the following environment variables in the client environment:

    • JMSDEBUG: Provides verbose debugging output from the client.

    • JMSJVMOPTS: Provides extra arguments to the JVM loaded by the client.

    • ULOGPFX: Configures the pathname and file prefix where the error log file is placed.

Client Packaging Requirements

You will need to include the JMS C API library and other files when you package the C application.

Include the following files along with a C application executable:

  • A supported JVM for your operating system.

  • If WebLogic Server is not installed on the machine that will run the application: the WebLogic JMS client jar(s) – usually the wlthint3client.jar. See Developing a WebLogic Thin T3 Client in Developing Standalone Clients for Oracle WebLogic Server.

  • If the client executable dynamically links its JMS C library, include the JMS C API library specific to the platform on which your application will run. JMS C API dynamic libraries can be copied from your WebLogic Server install at:

    • server/native/aix/ppc/libjmsc.so

    • server/native/aix/ppc64/libjmsc.so

    • server/native/hpux11/IPF64/libjmsc.so

    • server/native/linux/i686/libjmsc.so

    • server/native/linux/ia64/libjmsc.so

    • server/native/linux/s390x/libjmsc.so

    • server/native/linux/x86_64/libjmsc.so

    • server/native/solaris/sparc/libjmsc.so

    • server/native/solaris/sparc64/libjmsc.so

    • server/native/solaris/x64/libjmsc.so

    • server/native/solaris/x86/libjmsc.so

    • server/native/win/32/jmsc.dll

    • server/native/win/64/jmsc.dll

    • server/native/win/x64/jmsc.dll

Workarounds for Client Failure Thread Detach Issue

A C program that uses the JMS C client library may fail when its implicitly embedded JVM fails.

The JMS client failure could be related to a known, intermittent race-condition that occurs only with certain JVM products. The likelihood of failure can change based on the JVM version and patch level, operating system, and hardware combination. Specifically, the JMS C-Client library implicitly attaches C-threads to the JVM, but fails to detach them when it is done with them. The suggested workarounds are as follows:

  • Add code in the client to detach the JVM from any C thread that exits and that has previously called into the JMS C-API.

  • Do not allow a C thread that has previously called into the JMS C-API to exit before the entire process exits.

The sample Java JNI code shown in Example 16-1 describes how to detach the thread from the JVM.

Example 16-1 Sample Java JNI Code

#include <jni.h>

...

JavaVM *jvmList[JVM_LIST_SIZE];
jsize retSize = -1;
jint retVal = JNI_GetCreatedJavaVMs(jvmList, JVM_LIST_SIZE, &retSize);
if ((retVal != 0) || (retSize < 1) ) {
  printf('ERROR: got %d/%d on JNI_getCreatedJavaVMs\n', retVal, retSize);
  return;
}
printf('INFO: got %d/%d on JNI_getCreatedJavaVMs\n', retVal, retSize);
/* The following line assumes that there's exactly one JVM: */
(*(jvmList[0]))->DetachCurrentThread(jvmList[0]);

If a program is not directly making JNI calls already, it may be necessary to add compiler and linker parameters for access to the Java JNI libraries. For example, in MicroSoft Visual C++, do the following:

  • Add -I$(JAVA_HOME)/include and -I$(JAVA_HOME)/include/win32 to the compile

  • Add $(JAVA_HOME)/lib/jvm.lib to the link