Skip Headers
Oracle® Fusion Middleware Using the WebLogic JMS Client for Microsoft .NET for Oracle WebLogic Server
12c Release 1 (12.1.1)

Part Number E24386-02
Go to Documentation Home
Home
Go to Table of Contents
Contents
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
PDF · Mobi · ePub

4 Programming Considerations

This chapter provides programming considerations and best practices to use when creating a JMS .NET client application.

Using WebLogic JMS Extensions

Table 4-1 lists the WebLogic JMS extensions that are supported in this release of the JMS .NET client. There are several ways that messaging can be configured:

In some cases, there are differences in the way that an extension is configured, or in the behavior, between a JMS .NET client and a Java client. For example, some extensions cannot be enabled programmatically using the JMS .NET API, and can only be enabled via configuration. The following table summarizes the differences. Additional details, if required, are provided in the subsequent sections.

Table 4-1 WebLogic JMS Extensions Supported in the JMS .NET Client

Feature Configurable on Connection Factory Configurable on the Server Java API JMS .NETAPI Comments

Distributed Destinations (Uniform and Weighted)

For more information, see:

Yes

Yes

No

No

 

Flow Control Producers

For more information, see: Controlling the Flow of Messages on JMS Servers and Destinations in Performance and Tuning for Oracle WebLogic Server

Yes

Yes

No

No

 

Blocking producers during quota conditions

For more information, see Defining a Send Timeout on Connection Factories in Performance and Tuning for Oracle WebLogic Server

Yes

Yes

No

No

 

Foreign destinations for remote instances of WebLogic Server

For more information, see Configuring Foreign Server Resources to Access Third-Party JMS Providers in Configuring and Managing JMS for Oracle WebLogic Server

No

Yes

No

No

See Interoperating with Previous WebLogic Server Releases.

Imported store-and-forward (SAF) destinations

For more information, see Imported SAF Destinations in Configuring and Managing Store-and-Forward for Oracle WebLogic Server

No

Yes

No

No

 

Redelivery limit

For more information, see Setting a Redelivery Limit for Messages in Programming JMS for Oracle WebLogic Server

No

Yes

Yes

No

 

Redelivery delay

For more information, see Setting a Redelivery Delay for Messages in Programming JMS for Oracle WebLogic Server

Yes

No

Yes

No

 

Error destinations

For more information, see Configuring an Error Destination for Undelivered Messages in Programming JMS for Oracle WebLogic Server

No

Yes

No

No

 

"WLDestination.getCreateDestinationArgument"

No

No

Yes

Yes

 

No Acknowledge Mode

For more information, see Using NO_ACKNOWLEDGE in Programming JMS for Oracle WebLogic Server

No

No

Yes

Yes

 

Unit-of-Order

For more information, see:

Yes

Yes

Yes

Yes

See Unit-of-Order.

Scheduled message delivery

For more information, see Setting Message Delivery Times in Programming JMS for Oracle WebLogic Server

Yes

Yes

Yes

Yes

See Message Delivery Time.

Asynchronous consumer messages maximum pipeline

Yes

No

Yes

No

 

Message Compression

For more information, see Message Compression in Programming JMS for Oracle WebLogic Server

Yes

No

Yes

No

See Message Compression.

Quotas

For more information, see Defining Quota in Performance and Tuning for Oracle WebLogic Server

No

Yes

No

No

 

One-way message sends

For more information, see Using One-Way Message Sends For Improved Non-Persistent Messaging Performance in Performance and Tuning for Oracle WebLogic Server

Yes

No

No

No

See One-Way Message Sends.

Acknowledge policy

For more information, see "JMS Connection Factory: Configuration: Client" in the Oracle WebLogic Server Administration Console Help

Yes

No

No

No

 

Automatically include user-id as message property JMSXUserID

Yes

Yes

No

No

See Include user-id as JMSXUserId.

Get number of delivery attempts as message property JMSXDeliveryCount

No

No

No

No

See Message Delivery Attempts.


Message Compression

In this release, automatic message compression is not supported for client sends between the JMS .NET client and the JMS .NET client host running on WebLogic Server. However, if the compression settings are set on the connection factory, message compression behavior between the .NET client host and the destination is the same as that of the Java client. The behavior is as follows:

  • If the client host and destination run on different instances of WebLogic Server, then a sent message is automatically compressed on the client host.

  • If the client host and destination run on the same instance of WebLogic Server, then no sent message compression will occur.

Compressed messages are decompressed by the JMS .NET client host on the server side when they are received by the .NET client.

For more information, see Message Compression in Programming JMS for Oracle WebLogic Server

Unit-of-Order

The method used to specify Unit-of-Order (UOO) in the JMS .NET API differs from the Java API. To set Unit-of-Order in the JMS .NET API, add a string property named Constants.MessagePropertyNames.UNIT_OF_ORDER_PROPERTY_NAME to the message with the desired UOO.

For more information, see Using Message Unit-of-Order in Programming JMS for Oracle WebLogic Server

Message Delivery Time

The method used to specify message delivery times in the JMS .NET API differs from the Java API. To set message delivery times in the JMS .NET API, add a property of type long named Constants.MessagePropertyNames.DELIVERY_TIME_PROPERTY_NAME to the message, where the value is the number of milliseconds in the future in which the message will be delivered.

One-Way Message Sends

Although you can configure one-way message sends on the connection factory, this behavior is not fully supported in the JMS .NET client. Messages sent as one-way sends will actually be two- way sends between the .NET client and the .NET client host, and one-way sends between the .NET client host and the JMS connection host.

Include user-id as JMSXUserId

The optional JMSXUserId system-generated message property on received messages specifies the credential of the original sender. To enable this property, configure the Attach Sender Credential attribute on destinations, distributed destinations, or templates, and configure the Attach JMSXUserId attribute on connection factories. To retrieve, call msg.GetStringProperty(Constants.MessagePropertyNames.USER_ID_PROPERTY_NAME).

Message Delivery Attempts

The JMSXDeliveryCount system-generated message property on received messages specifies the number of message delivery attempts. The first attempt is 1. To retrieve the value, call msg.GetIntProperty(Constants.MessagePropertyNames.DELIVERY_COUNT_PROPERTY_NAME.

Limitations of Using the WebLogic JMS .NET Client

The following sections describe the JMS features that are not supported in the JMS .NET client.

Unsupported JMS 1.1 Standard Features

In this release, the following JMS 1.1 standard features are not supported:

  • Creating and closing temporary destinations (javax.jms.TemporaryQueue and javax.jms.TemporaryTopic). The JMS .NET client can still produce messages to temporary destinations created by a Java client if the destination objects are obtained from the JMSReplyTo header of received messages.

  • javax.jms.QueueRequester and javax.jms.TopicRequester. (These helper classes are related to temporary destinations.)

  • Queue browsers: javax.jms.QueueBrowser.

  • Queue and Topic interfaces (QueueConnectionFactory, TopicConnectionFactory, QueueConnection, TopicConnection, QueueSession, TopicSession). These queue and topic interfaces are legacy JMS 1.0.2 interfaces that have been superseded by the JMS 1.1 common interfaces.

Unsupported JMS 1.1 Optional Features

In this release, the following JMS 1.1 optional features are not supported:

  • XA interfaces (XAConnectionFactory, XAConnection, and XASession).

  • Participation in global XA transactions (See Transactions).

  • Connection Consumer and Server session pools (javax.jms.ConnectionConsumer, ServerSessionPool, and ServerSession). These are optional capabilities that have been superseded by Java EE MDBs, and are not supported by the WebLogic Java JMS client.

  • MessageProducer.setDisableMessageTimestamp method. Note that the WebLogic JMS Java client ignores this method.

Unsupported WebLogic JMS Extensions

In this release, the following WebLogic JMS extensions are not supported:

  • SSL

  • HTTP tunneling

  • SAF Client—See Reliably Sending Messages Using the JMS SAF Client in Programming Stand-alone Clients for Oracle WebLogic Server

  • Multicast Subscribers—See Using Multicasting with WebLogic JMS in Programming WebLogic JMS

  • Automatic Reconnect—See Automatic JMS Client Failoverin Programming JMS for Oracle WebLogic Server

  • Unit-of-Work—If a .NET client attempts to set a UOW property on a message, a Weblogic.Messaging.MessageException is generated. In addition, a .NET consumer cannot receive UOW messages with deserializable content that are sent by a Java client. In this case, the consumer gets a MessageFormatException if it calls the ObjectMessage.getObject() method on the ObjectMessage. Note that while Unit-of-Work is not supported, the more commonly used Unit-of-Order extension is fully supported. For more information about Unit-of-Order, see Unit-of-Order.

    Note:

    The JMS .NET API does not provide extensions for programmatically configuring JMS resources (for example, topics and queues). In Java, programmatic configuration is accomplished using JMX MBeans or the weblogic.jms.extensions.JMSModuleHelper helper class. Alternative ways to configure JMS include WLST scripting and the WebLogic Administration Console.

Transactions

In this release, the JMS .NET client supports transacted sessions as defined in the JMS Specification only. Transacted sessions provide a standard local transaction capability. As with the Java client, one or more WebLogic JMS destinations from within the same cluster may participate in a transacted session local transaction, but no other resources may participate (such as JMS servers in other clusters, databases, or foreign JMS providers).

Global XA transactions are not supported, therefore JMS cannot participate in a .NET transaction. The XA setting of the connection factory is ignored by the .NET client. The JMS NET client operations cannot participant in any .NET transactions.

Exchanging Messages Between Different Language Environments

The following Java JMS message types can be exchanged between a .NET producer and a Java or C consumer, and vice versa:

An ObjectMessage type, however, can be sent from one language and received by another, but the message cannot be interpreted unless it is written in the same language. The producer and consumer of an OBJECTMESSAGE type must be written in the same language, either C# or Java. If a mismatch occurs; that is, if a .NET ObjectMessage is received by a Java consumer, or a Java ObjectMessage is received by a .NET consumer, then message.getObject() throws a MessageFormatException.

Specifying the URL Format

The Provider_URL may contain multiple addresses, separated by commas, using the following format:

t3://address [,address]...

where a particular address may specify multiple port ranges.

The syntax for specifying multiple addresses is as follows:

address = hostlist : portlist

where

hostlist = hostname [, hostname]...
portlist = portrange [+ portrange]...
portrange = port [- port]

Use port -port to indicate a port range, and + (plus sign) to separate multiple port ranges.

Table 4-2 provides sample URL formats.

Table 4-2 URL Format Examples

This format . . . Can also be specified as . . .
t3://hostA:7001
t3://hostA,hostB:7001,hostC:7002
t3://hostA:7001,hostB:7001,hostC:7002
t3://hostA:7001+7005+7007,hostB:7001
t3://hostA:7001,hostA:7005,hostA:7007,
hostB:7001
t3://hostA:7001-7003+7005+7007,hostB:8001
t3://hostA:7001,hostA:7002,hostA:7003,
hostA:7005,hostA:7007,hostB:8001

Using DNS Alias Host Names

You can also specify DNS alias host names, which are expanded into multiple hosts. For example, if a DNS alias mycluster resolves to host1,host2, then the URL t3://mycluster:7001 expands into the address list: t3://host1:7001,host2:7001. Contexts that are created with the URL will always retry with host2 if host1 is unreachable. DNS aliases are typically configured by network administrators.

Implementing Security With the JMS .NET Client

You need to be aware of the following security considerations when creating a JMS .NET client:

Configuring Logging and Debugging

Basic logging and debugging is available for the server-side transport and .NET client host running on WebLogic Server.

Server Side

To enable debugging on the server side, use the following commands:

-Dweblogic.debug.DebugJMSDotNetT3Server=true
-Dweblogic.debug.Debug.JMSDotNetProxy=true 

Client Side

Client-side logging and debugging are enabled and controlled by various configuration settings in the application configuration file. For generated build files, the application configuration file is named yourapplicationname.exe.config, where yourapplicationname is the name of the application that runs the messaging client.

Example 4-1 provides the XML content that needs to be added to your application configuration file to configure logging and debugging. The subsequent sections provide additional details about each of the different settings. If you have an existing yourapplicationname.exe.config file, add the XML content shown in the following listing to the file. Otherwise, you can create one and locate it in the same directory that contains the yourapplicationname.exe file.

Note:

If you are using Visual Studio, the logging and debugging settings shown in Example 4-1 need to be added to the App.config file. Follow the instructions on the Microsoft Web site http://msdn.microsoft.com/en-us/library/ms184658.aspx to add an App.config file to your C# project inside a Visual Studio environment.

Example 4-1 XML File Content for yourapplicationname.exe.config File

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <!-- To forward log output to a file, please uncomment the following line, and replace the file name with the desired one -->
    <!--- <add key="wweblogic.debug.JMSDotNet.config.LogFileName" value="c:\test\MyLogFile.log" /> -->
    
    <!-- To prevent log messages from displaying to the console, use the value 'false' -->
    <!-- <add key="weblogic.debug.JMSDotNet.config.IsLogToConsole" value="false" /> -->    
  </appSettings>
  <system.diagnostics>
    <switches>
      <!-- Please set the switch value as desired for logging to each Category -->
      <!-- value for Off=0, Error=1, Warning=2, Info=3, Verbose=4    -->
 
      <!-- if "AllLogger" is enabled (no zero for the value), every individual category is set to the same level as the AllLogger,
            no matter how individual category's value is set -->
      <add name="weblogic.debug.JMSDotNet.All" value="0" />
      <add name="weblogic.debug.JMSDotNet.Socket" value="0" />
      <add name="weblogic.debug.JMSDotNet.T3" value="0" />
      <add name="weblogic.debug.JMSDotNet.Transport" value="0" />
      <add name="weblogic.debug.JMSDotNet.PhysicalMsg" value="0" />
      <add name="weblogic.debug.JMSDotNet.LogicalMsg" value="0" />
    </switches>
  </system.diagnostics>
</configuration>

Message Output

Use the <appSettings> element to specify whether log messages are output to the console or saved to a file as shown in Table 4-3.

Table 4-3 appSettings Values

Key Value Setting
wweblogic.debug.JMSDotNet.config.LogFileName

String

Full path and file name for the log file, for example c:\test\MyLogFile.log.

NOTE: The default log file size limit is 500KB. Each time the log file reaches this size, the server renames the log file and creates a new MyLogFile.log to store new messages. By default, the rotated log files are numbered in order of creation, for example MyLogFile.log.0, MyLogFile.log.1, MyLogFile.log.2, ..., with MyLogFile.log.0 containing the latest log messages.

weblogic.debug.JMSDotNet.config.IsLogToConsole

Boolean

  • True — Displays log messages to the console

  • False — Does not display log messages to the console


Log Categories and Levels

Client-side logging is grouped into the following categories:

  • Socket

  • T3

  • Transport

  • PhysicalMsg

  • LogicalMsg

  • All (represents all individual categories listed above)

For each of the categories, you can specify any of these logging levels:

Off(0), Error(1), Warning(2), Info(3), Verbose(4)

Note that the severity level on the All category overrides the setting on each individual category.

Understanding Socket and Threading Behavior

WebLogic JMS .NET clients share the same WebLogic Server T3 port as other types of WebLogic clients. When an IContext initial context is created by a .NET client using the ContextFactory class, the client specifies a URL that references a T3 capable port on the server, and a socket pair is implicitly created to service the requested network connection. The socket pair consists of one socket on the client and another socket on the WebLogic Server JMS .NET client host. All JMS operations on JMS objects obtained from the .NET context route through the implicit network connection of the context.

If two concurrent IContext initial context instances on the same .NET CLR connect to the same WebLogic Server JMS .NET client host, then two network connections are created. Each network connection has its own pair of sockets: a server-side socket and a client-side socket. Therefore, when two network connections are created, two sockets are created on the CLR client and two sockets are created on the WebLogic Server acting as the JMS .NET client host. This contrasts with WebLogic Java clients, which automatically detect and close duplicate network connections to a remote JVM and, instead, implicitly multiplex all traffic to and from a particular remote JVM over a single network connection.

A server-side socket for a JMS .NET client is serviced by the same WebLogic Server socket-reader muxer thread pool as other types of WebLogic clients. When working on behalf of JMS .NET client requests, the socket-reader muxer thread pool reads the incoming requests from the socket and dispatches work into the WebLogic Server default thread pool which, in turn, processes the requests and sends the responses back to the client.

On a JMS .NET client, a new internal thread is automatically created for each network connection (that is, per IContext initial context instance). This dedicated thread reads all incoming data on the client socket and dispatches the related work into the CLR thread pool. This means that asynchronous message event handlers in the .NET client application run in the CLR thread pool.

Note:

The CLR thread pool is supplied by the .NET Framework System.Threading.ThreadPool class. There is one thread pool per process. The thread pool has a default size of 25 threads per available processor, however, you can change the number of threads in the thread pool using the ThreadPool.SetMaxThreads method. Each thread in the thread pool uses the default stack size and runs at the default priority. For more information, refer to the Microsoft .NET Framework documentation for the System.Threading.ThreadPool class.

For JMS .NET applications that create many concurrent initial contexts that all connect to the same WebLogic Server .NET client host, you may obtain performance improvements by modifying the application so that it uses a single, shared initial context. A shared context ensures that the client only creates a single network connection.

Data Conversion Between Java and .NET

Endian Conversions

Java and .NET use different byte order formats for storing primitive types:

  • Microsoft Windows .NET uses the Little-Endian (low-order) format

  • Java uses the Big-Endian (high-order) format

To support interoperability between Java and .NET, data is transferred over the network using the Big-Endian format. When a .NET application uses the JMS .NET API to read and write primitives, data is automatically converted between Big-Endian and Little-Endian, as needed. For example, if you use BytesMessage.WriteInt in the JMS .NET API, the data is always stored as Big Endian and can be read using both the Java API and the JMS .NET API bytes message read integer methods.

For specialized applications that do not use the JMS .NET API to pass primitives, but instead transfer primitive data using raw byte arrays, you need to manually convert the byte format to Big Endian when communicating with Java. If you need to perform a manual Endian conversion in your application, you can use the following helper methods from the utility class WebLogic.Messaging.Transport.Util.EndianConvertor provided in the JMS .NET client library:

public static char SwitchEndian(char x)
public static short SwitchEndian(short x)
public static int SwitchEndian(int x)
public static long SwitchEndian(long x)
public static ushort SwitchEndian(ushort x)
public static uint SwitchEndian(uint x)
public static ulong SwitchEndian(ulong x)
public static double SwitchEndian(double x)
public static float SwitchEndian(float x)
public static byte[] SwitchEndian(byte[] x) 

For example, the standard .NET classes System.IO.BinaryReader and System.IO.BinaryWriter for reading and writing primitives to raw byte arrays use Little Endian. The following code snippet illustrates how to store and retrieve an integer to/from a .NET byte array:

binaryWriter.WriteInt(EndianConverter.SwitchEndian(i))
i=EndianConverter.SwitchEndian(binaryReader.ReadInt())

Signed and Unsigned Byte Conversions

With the exception of the byte data type, there is an equivalent C# data type, with the same name and definition, for every Java primitive data type. The following table lists the different names used for signed and unsigned bytes in C# and Java.

Table 4-4 Byte Primitive Data Type in C# and Java

C# Java Description
byte
N/A

Unsigned byte

sbyte
byte

Signed byte


As shown in Table 4-4, Microsoft .NET supports both byte (unsigned byte) and sbyte (signed byte) as primitive data types, but Java supports only byte (signed byte) as a direct primitive type. The standard convention in both languages is to use the byte data type; however, in .NET this represents an unsigned byte and in Java this represents a signed byte.

For interoperability between .NET and Java, the JMS .NET client allows only the use of the signed byte for reading and writing bytes. There is no difference between signed bytes and unsigned bytes when the byte value is 127 or less. An unsigned byte with a value of 127 or less is stored as an sbyte. However, if a .NET client needs to store an unsigned byte with a value greater than 127 in a signed byte, it needs to be converted from a signed byte to an unsigned byte. The following samples illustrate conversion methods that you can use to read and write an unsigned byte as a signed byte:

  • Byte Conversion in C#

    An unsigned byte value of 255 can be passed as a signed byte as follows:

    • byte unsignedByteValue = 255;

    • sbyte signedByteValue = unchecked ( (sbyte)unsignedByteValue ); // converted signed value=-1

    Similarly, you can use the following method to convert a signed byte value to an unsigned byte value:

    • sbyte signedByteValue = -1;

    • byte unsignedByteValue = unchecked ( (byte)signedByteValue ); // converted unsigned value=255

  • Byte Conversion in Java

    The unsigned value can be read as a signed byte and converted to an unsigned byte value as follows:

    • byte signedByteValue = -1;

    • int unsignedByteValue = 0xFF & signedByteValue; //converted signed value = 255

    An unsigned value can be written as follows:

    • Int unsignedByteValue = 255;

    • byte signedByteValue = 0xFF & unsignedByteValue; // converted signed value=-1

The JMS .NET API only allows for storing single bytes as signed bytes. When the JMS .NET API is used to retrieve sbyte values as short, int, long, or string, the value is treated as an sbyte, not an unsigned byte. For example, if the unsigned byte value 255 is stored using message.SetByteProperty("myvalue", unchecked( (sbyte)((byte)255) )), a call to message.GetByteProperty("myvalue")or message.GetShortProperty("myvalue") returns "-1".

Byte Array Transfers

When transferring byte arrays from the JMS .NET client to WebLogic JMS, all byte arrays (byte[]) are passed as is (that is, there is no conversion from unsigned to signed.) Therefore, no data is lost in the translation.

Time Conversions

The WebLogic JMS .NET API represents dates and times using Java rather than .NET conventions. The JMSTimestamp and JMSExpiration attributes of the WebLogic.Messaging.IMessage message interface are type long and contain a millisecond absolute time value as specified in the Java programming language. The Java millisecond absolute time value is the difference, measured in milliseconds, between a given time and midnight, January 1, 1970 UTC.

The following examples demonstrate how to convert between .NET times and Java millisecond absolute time values.

Example 4-2 Example C# Code for Converting the Current .NET Time to Java Millisecond Time

// Example:  C# code for converting the current .NET time to Java millisecond time
DateTime baseTime = new DateTime(1970, 1, 1, 0, 0, 0);
DateTime utcNow = DateTime.UtcNow;
long timeInMillis = (utcNow.Ticks - baseTime.Ticks)/10000;
Console.WriteLine(timeInMillis);

Example 4-3 Example C# Code for Converting Java Millisecond Time to .NET Time

// Example:  C# code for converting Java millisecond time to .NET time
DateTime baseTime = new DateTime(1970, 1, 1, 0, 0, 0);
long utcTimeTicks = (timeInMillis * 10000) + baseTime.Ticks;
DateTime utcTime = new DateTime(utcTimeTicks, DateTimeKind.Utc);
Console.WriteLine(utcTime);
Console.WriteLine(utcTime.ToLocalTime());

Best Practices

The following list identifies best practices to use when creating a JMS .NET client application: