Enterprise J2ME Developing Mobile Java Applications [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Enterprise J2ME Developing Mobile Java Applications [Electronic resources] - نسخه متنی

Michael Juntao Yuan

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید



10.4 The IBM WebSphere MQ Everyplace


The IBM WebSphere MQ Everyplace (or, MQseries Everyplace: WMQe) is another mobile MOM server. The version of WMQe covered in this book is v2.0. It provides a set of JMS-like APIs in the com.ibm.mqe package. The WMQe API supports features beyond the JMS specification, such as message compression and built-in encryption. In addition, it supports a rich set of server administration APIs. For example, it allows the developer to manage queues and server settings programmatically. WMQe supports JMS through an optional adapter JAR file.


10.4.1 A Truly Mobile MOM Solution


WMQe runs on Windows, Linux, and many flavors of UNIX OSs. But like the IBM SMF (see Chapter 4) and DB2e (DB2 Everyplace; see Chapter 11), its most distinguished feature is that the WMQe server also runs on mobile devices! This allows the ultimate mobility for the middleware server and the mobile network it serves. WMQe runs natively on major mobile platforms, including PocketPC, Symbian OS, Palm OS, Embedded Linux, and QNX. It also runs on any device that supports PersonalJava or IBM's WebSphere Micro Environment. One of those Java environments is required for the Java API to work.

The portable WMQe server allows a TV settop box or a PDA to be the messaging gateway for other pervasive devices in the in-home or in-hand network. WMQe can be integrated with SMF and DB2e to build sophisticated mobile enterprise applications. As we discussed in section 4.5, locally placed mobile middleware can drastically improve overall system performance, availability, and reliability.

Now, let's have a look at the HelloWorld example bundled in the WMQe distribution. It covers some simple administration APIs of WMQe and highlights the differences between WMQe and JMS.


WMQe on Mobile Phones


Fully featured WMQe server runs on PersonalJava and CDC/FP devices, but not on CLDC/MIDP devices. On those low-end devices, we can only run WMQe client with a limited number of compressors and encryptors.


10.4.2 HelloWorld Code Walk Through


The HelloWorld example demonstrates how to use a queue manager to send and receive simple messages. The underlying persistence mechanism for messages is the local file system. The queue manager and its queues (message, system, and administration) are all stored in a directory. First, we have to configure the queue manager. Listing 10.9 illustrates how to set up and initialize the appropriate file system directory and files for the queue manager.

Listing 10.9. Configure the queue manager



String queueManagerName = "HelloWorldQM";
String baseDirectoryName = "./QueueManagers/" + queueManagerName;
// Create all the configuration information needed
// to construct the queue manager in memory.
MQeFields config = new MQeFields();
// Construct the queue manager section parameters.
MQeFields queueManagerSection = new MQeFields();
queueManagerSection.putAscii(MQeQueueManager.Name,
queueManagerName);
config.putFields(MQeQueueManager.QueueManager,
queueManagerSection);
// Construct the registry section parameters.
// In this example, we use a public registry.
MQeFields registrySection = new MQeFields();
registrySection.putAscii(MQeRegistry.Adapter,
"com.ibm.mqe.adapters.MQeDiskFieldsAdapter");
registrySection.putAscii(MQeRegistry.DirName,
baseDirectoryName + "/Registry");
config.putFields("Registry", registrySection);
// Construct a queue manager configuration
// utility object.
MQeQueueManagerConfigure configurator =
new MQeQueueManagerConfigure(config,
"com.ibm.mqe.adapters.MQeDiskFieldsAdapter" +
":" + baseDirectoryName + "/Queues");
// Define a queue manager.
configurator.defineQueueManager();
// Define some queues on the queue manager.
configurator.defineDefaultAdminQueue();
configurator.defineDefaultAdminReplyQueue();
configurator.defineDefaultDeadLetterQueue();
configurator.defineDefaultSystemQueue();
// Close the queue manager configuration utility.
configurator.close();

After the underlying disk files are properly initiated and configured, we can start the queue manager (Listing 10.10). We have to pass the configured directory to the MQeQueueManager object.

Listing 10.10. Start the queue manager



String queueManagerName = "HelloWorldQM";
String baseDirectoryName = "./QueueManagers/" + queueManagerName;
// Create all the configuration information
// needed to construct the queue manager in memory.
MQeFields config = new MQeFields();
// Construct the queue manager section parameters.
MQeFields queueManagerSection = new MQeFields();
queueManagerSection.putAscii(MQeQueueManager.Name,
queueManagerName);
config.putFields(MQeQueueManager.QueueManager,
queueManagerSection);
// Construct the registry section parameters.
// In this example, we use a public registry.
MQeFields registrySection = new MQeFields();
registrySection.putAscii(MQeRegistry.Adapter,
"com.ibm.mqe.adapters.MQeDiskFieldsAdapter");
registrySection.putAscii(MQeRegistry.DirName,
baseDirectoryName + "/Registry");
config.putFields("Registry", registrySection);
myQueueManager = new MQeQueueManager();
myQueueManager.activate(config);

Now, using the MQeQueueManager instance, the client application can create queues and send out messages. Listing 10.11 demonstrates both sending and receiving messages via the system default queue.

Listing 10.11. Send and receive a message via the default queue



public void put() throws Exception {
MQeMsgObject msg = new MQeMsgObject();
// Add my hello world text to the message.
msg.putUnicode("myFieldName", "Hello World!");
myQueueManager.putMessage(queueManagerName,
MQe.System_Default_Queue_Name, msg, null, 0L);
}
public void get() throws Exception {
MQeMsgObject msg = myQueueManager.getMessage(queueManagerName,
MQe.System_Default_Queue_Name,
null, null, 0L);
if (msg != null) {
if (msg.contains("myFieldName")) {
String textGot = msg.getUnicode("myFieldName");
System.out.println(
"Message contained the text '" + textGot + "'");
}
}
}

The shutdown process involves closing the queue manager object and removing the underlying files (Listing 10.12).

Listing 10.12. Shutdown the queue manager and delete underlying files



// Close the queue manager
myQueueManager.closeQuiesce(QUIESCE_TIME);
myQueueManager = null;
// Delete the configured directory.
String queueManagerName = "HelloWorldQM";
String baseDirectoryName = "./QueueManagers/" + queueManagerName;
// Create all the configuration information needed
// to construct the queue manager in memory.
MQeFields config = new MQeFields();
// Construct the queue manager section parameters.
MQeFields queueManagerSection = new MQeFields();
queueManagerSection.putAscii(MQeQueueManager.Name,
queueManagerName);
config.putFields(MQeQueueManager.QueueManager,
queueManagerSection);
// Construct the registry section parameters.
// In this example, we use a public registry.
MQeFields registrySection = new MQeFields();
registrySection.putAscii(MQeRegistry.Adapter,
"com.ibm.mqe.adapters.MQeDiskFieldsAdapter");
registrySection.putAscii(MQeRegistry.DirName,
baseDirectoryName + "/Registry");
config.putFields("Registry", registrySection);
System.out.println("Queue manager " +
queueManagerName + " will now be deleted.");
MQeQueueManagerConfigure configurator =
new MQeQueueManagerConfigure();
configurator.activate(config,
"com.ibm.mqe.adapters.MQeDiskFieldsAdapter"
+ ":" + baseDirectoryName + "/Queues");
// Remove the configured entries for the queues
// we defined.
configurator.deleteSystemQueueDefinition();
configurator.deleteDeadLetterQueueDefinition();
configurator.deleteAdminReplyQueueDefinition();
configurator.deleteAdminQueueDefinition();
// Remove the queue manager itself.
configurator.deleteQueueManagerDefinition();
configurator.close();


10.4.3 Storage Adapters


Adapters map WMQe's high-level messaging concepts to underlying, concrete implementations. In the above example, we used the MQeDiskFieldsAdapter class to persist message queues to disk files. A disk file system is not available on all J2ME devices. Even for devices that support disk files, they might not be the most efficient persistence storage. Other persistence mechanisms must be supported if WMQe is to run efficiently on a large variety of devices. All storage adapters inherit from the MQeAdapter class. Table 10.2 lists the methods the storage adapters could override.

Table 10.2. Methods in the MQeAdapter Class

Method

Description

activate

Initiates and activates an adapter. It is used only once in the life cycle.

open

Opens an adapter for use.

control

Defines the behaviors of the adapter.

close

Closes an adapter.

WMQe bundles the following standard storage adapters (Table 10.3). Custom storage adapters can be developed by directly subclassing the MQeAdapter class.

Table 10.3. Standard Storage Adapters

Adaptor

Description

MQeDiskFieldsAdapter

Persists messages to disk files.

MQeMappingAdapter

Enables the use of long file names but maps those long file names to shorter formats (e.g., 8.3 format).

MQeMemoryFieldsAdapter

Persists data to memory.

MQeMidpFieldsAdapter

Persists data to MIDP RMS record stores.


10.4.4 The Administration Queue


Any queue manager can be configured at runtime through a special administration queue. Basically, the user or developer can send specially formatted messages to the administration queue and the queue manager will act accordingly.

For example, in the Hello World sample, we only demonstrated how to pass messages through a local queue. Through the administration queue, we can configure the queue manager to manipulate a remote queue or listen for incoming messages at a specified server port (Listing 10.13). We can see that WMQe provides convenient ways to encrypt and compress remote messages for the best security and performance.

Listing 10.13. Administration messages for remote queues and message listeners



// Create a connection from this queue manager
// to a remote queue manager
public void createConnection (String onQMgr,
String name, String parms,
String options) throws Exception {
// TCP/IP adapter
String adapter = "com.ibm.mqe.adapters.MQeTcpipHistoryAdapter";
// Or MIDP HTTP adapter for MIDP clients
// String adapter = "com.ibm.mqe.adapters.MQeMidpHttpAdapter";
MQeConnectionAdminMsg msg = new MQeConnectionAdminMsg();
MQeFields msgTest = primeAdminMsg(onQMgr, msg);
msg.setName(name);
// Set the admin action to create a new queue
msg.create(adapter, parms, options,
"DefaultChannel", "Route to: " + name);
MQeAdminMsg respMsg = processAdminMsg(onQMgr, msg);
checkAdminReply(respMsg);
}
// Create a remote listener for the queue manager
public void createListener (String listenerName) throws Exception {
// Part 1 - Create the listener
MQeCommunicationsListenerAdminMsg msg =
new MQeCommunicationsListenerAdminMsg();
MQeFields msgTest =
primeAdminMsg(queueManager.getName(), msg);
String listenAdapter =
"com.ibm.mqe.adapters.MQeTcpipHistoryAdapter";
int listenPort = 8092;
msg.setName(listenerName);
msg.create(listenAdapter, listenPort);
// Send the admin message, wait for a reply
// and check for success.
MQeAdminMsg respMsg = processAdminMsg(queueManager.getName(), msg);
checkAdminReply(respMsg);
// Part 2 - Start the listener
msg = new MQeCommunicationsListenerAdminMsg();
MQeFields msgTest2 = primeAdminMsg(queueManager.getName(), msg);
msg.setName(listenerName);
msg.start();
respMsg =
processAdminMsg(queueManager.getName(), msg);
checkAdminReply(respMsg);
}
// Create a remote queue
public void createRemoteQueue( String onQMgr,
String qm, String q, boolean sync,
String compressor, String cryptor)
throws Exception {
MQeRemoteQueueAdminMsg msg = new MQeRemoteQueueAdminMsg();
primeAdminMsg(onQMgr, msg);
msg.setName(qm, q);
// Define the parameters of the new queue using
// an MQeFields object
MQeFields parms = new MQeFields();
parms.putUnicode(MQeQueueAdminMsg.Queue_Description,
"Remote Queue " + q + " on qm " + onQMgr);
// Add cryptor and/or compressor if required
if (compressor != null) {
parms.putAscii(MQeQueueAdminMsg.Queue_Compressor, compressor);
}
if (cryptor != null) {
parms.putAscii(MQeQueueAdminMsg.Queue_Cryptor, cryptor);
}
// Set queue as being accessed synchronously
// or asynchronously
if (sync) {
parms.putByte(MQeQueueAdminMsg.Queue_Mode,
MQeQueueAdminMsg.Queue_Synchronous);
} else {
parms.putByte(MQeQueueAdminMsg.Queue_Mode,
MQeQueueAdminMsg.Queue_Asynchronous);
}
// Set the admin action to create a new queue
// with these parameters and send it
msg.create(parms);
MQeAdminMsg respMsg = processAdminMsg(onQMgr, msg);
checkAdminReply(respMsg);
}
// Two utility methods for sending the receiving
// administration messages
// Give the message a unique identifier
public MQeFields primeAdminMsg(String onQMgr,
MQeAdminMsg msg) throws Exception {
// Set the target queue manager that will process
// this message, who to reply to and the 'style'
// of the message to be a request
msg.setTargetQMgr(onQMgr);
msg.putInt(MQe.Msg_Style, MQe.Msg_Style_Request);
msg.putAscii(MQe.Msg_ReplyToQ, MQe.Admin_Reply_Queue_Name);
msg.putAscii(MQe.Msg_ReplyToQMgr, onQMgr);
// Setup the correl id so we can match the
// reply to the request
msg.putArrayOfByte(MQe.Msg_CorrelID,
Long.toString(MQe.uniqueValue(), 16).getBytes());
// Ensure matching response message is retrieved
MQeFields msgTest = new MQeFields();
msgTest.putArrayOfByte(MQe.Msg_CorrelID,
msg.getArrayOfByte(MQe.Msg_CorrelID));
// Return the unique filter for this message
return msgTest;
}
// Process the message
public MQeAdminMsg processAdminMsg(String onQMgr,
MQeAdminMsg msg) throws Exception {
// Setup the match field to check for a matching
// reply message. The correl id is used as the
// match parameter.
MQeFields msgTest = new MQeFields();
msgTest.putArrayOfByte(MQe.Msg_CorrelID,
msg.getArrayOfByte(MQe.Msg_CorrelID));
// Put the admin message to the admin queue and
// return the reply
queueManager.putMessage(onQMgr,
MQe.Admin_Queue_Name, msg, null, 0);
MQeAdminMsg respMsg =
(MQeAdminMsg) waitForReply(onQMgr,
MQe.Admin_Reply_Queue_Name, msgTest);
return respMsg;
}


10.4.5 Communications Adapters


In Resources") and study the bundled documentation and tutorial examples.


/ 204