src.com.ibm.as400.access.UserQueue Maven / Gradle / Ivy
Show all versions of jt400 Show documentation
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: UserQueue.java
//
// The source code contained herein is licensed under the IBM Public License
// Version 1.0, which has been approved by the Open Source Initiative.
// Copyright (C) 2010-2010 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.access;
import java.io.CharConversionException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
/**
The UserQueue class represents an IBM i user queue object.
This class is currently in pre-BETA status and its existence serves as a placeholder
for code under development.
This class currently will only function when running on the IBM i using native Methods.
This class requires native method support which is still under development.
As a performance optimization, when running directly on IBM i, it is possible to use native
methods to access the user space from the current job. To enable this support, use the
{@link #setMustUseNativeMethods setMustUseNativeMethods()} method.
**/
public class UserQueue {
/** Queue type is first-in first-out */
public final static byte QUEUE_TYPE_FIRST_IN_FIRST_OUT = (byte) 0xc6;
/** Queue type is keyed */
public final static byte QUEUE_TYPE_KEYED = (byte) 0xd2;
/** Queue type is last-in first-out */
public final static byte QUEUE_TYPE_LAST_IN_FIRST_OUT = (byte) 0xd3;
// Use native methods when running natively;
private boolean mustUseNativeMethods_ = false;
AS400 system_;
String path_;
int handle_ = 0;
byte[] objectNameBytes_;
int dataSize_;
int keyLength_;
private byte queueType_;
UserQueueImpl impl_;
private Converter converter_;
/**
* Constructs a UserQueue object.
*
* @param system
* The system object representing the system on which the user queue
* exists.
* @param path
* The fully qualified integrated file system path name of the user
* queue.
* @throws UnsupportedEncodingException
* @throws CharConversionException
* @throws NullPointerException If passed invalid system or path.
**/
public UserQueue(AS400 system, String path)
throws UnsupportedEncodingException, CharConversionException {
if (Trace.traceOn_)
Trace.log(Trace.DIAGNOSTIC, "Constructing UserQueue object.");
if (system == null) {
Trace.log(Trace.ERROR, "Parameter 'system' is null.");
throw new NullPointerException("system");
}
if (path == null) {
Trace.log(Trace.ERROR, "Parameter 'path' is null.");
throw new NullPointerException("path");
}
system_ = system;
path_ = path;
converter_ = new Converter(system_.getCcsid(), null);
objectNameBytes_ = new byte[20];
Arrays.fill(objectNameBytes_, (byte) 0x40);
QSYSObjectPathName ifs = new QSYSObjectPathName(path, "USRQ");
// Set instance variables.
String library = ifs.getLibraryName();
byte[] libBytes;
libBytes = converter_.stringToByteArray(library);
String indexName = ifs.getObjectName();
byte[] indexNameBytes = converter_.stringToByteArray(indexName );
System.arraycopy(indexNameBytes, 0, objectNameBytes_, 0,
indexNameBytes.length);
System.arraycopy(libBytes, 0, objectNameBytes_, 10, libBytes.length);
//
// Pick the implementation. In the future this could be a PASE
// implementation or a remote implementation.
//
mustUseNativeMethods_ = true;
impl_ = new UserQueueImplILE(converter_);
}
/**
* Creates a user queue on the system. The queue will be created with the
* attributes provided.
*
* @param extendedAttribute
* The extended attribute of the user queue to be created.
* @param queueType
* The type of the queue, which indicates the sequences in which
* messages are to be dequeued from the queue. Valid values are
* QUEUE_TYPE_FIRST_IN_FIRST_OUT, QUEUE_TYPE_KEYED,
* QUEUE_TYPE_LAST_IN_FIRST_OUT.
* @param keyLength
* The length in bytes of the message key from 1 to 256, if the type
* of the queue is QUEUE_TYPE_KEYED. Otherwise, the value must be 0.
* @param maximumMessageSize
* The maximum allowed size of messages to be placed on the queue.
* The maximum size allowed is 64,000 bytes.
* @param initialNumberOfMessages
* The initial number of messages that the queue can contain.
* @param additionalNumberOfMessages
* The amount to increase the maximum number of messages value when
* the queue is full. If set to 0, the queue cannot be extended and
* an error message is returned when attempting to enqueue an
* additional entry.
* @param authority
* The public authority for the user space. This string must be 10
* characters or less. Valid values are:
*
* - *ALL
*
- *CHANGE
*
- *EXCLUDE
*
- *LIBCRTAUT
*
- *USE
*
- authorization-list name
*
* @param description
* A brief description of the user queue.
* @param replace
* Whether to replace an existing user queue. Valid values for this parameter are:
*
* - *NO Do not replace an existing user queue of the same name and library. *NO is the default.
*
- *YES Replace an existing user queue of the same name and library.
*
* The user queue being replaced is destroyed if both:
*
* - The user queue you are replacing is in the user domain.
*
- The allow user domain (QALWUSRDMN) system value is not set to *ALL or
* does not contain the library QRPLOBJ.
*
* If the QRPLOBJ library is specified in the QALWUSRDMN system value,
* then the replaced user-domain user queue is moved to the QRPLOBJ library.
* If the user queue is in the system domain, it is moved to the QRPLOBJ library,
* which is cleared at system IPL.
*
* @throws AS400SecurityException
* If a security or authority error occurs.
* @throws ErrorCompletingRequestException
* If an error occurs before the request is completed.
* @throws IOException
* If an error occurs while communicating with the system.
* @throws IllegalObjectTypeException
* If the object on the system is not the required type.
* @throws InterruptedException
* If this thread is interrupted.
* @throws ObjectAlreadyExistsException
* If the object already exists on the system.
* @throws ObjectDoesNotExistException
* If the library does not exist on the system.
* @throws AS400Exception If the create results in an AS400 erro message
**/
public void create(String extendedAttribute, byte queueType, int keyLength,
int maximumMessageSize, int initialNumberOfMessages,
int additionalNumberOfMessages, String authority, String description,
String replace) throws AS400SecurityException,
IOException, IllegalObjectTypeException,
InterruptedException, ObjectAlreadyExistsException,
ObjectDoesNotExistException, AS400Exception {
dataSize_ = maximumMessageSize;
byte[] extendedAttributeBytes = converter_.stringToByteArray(extendedAttribute);
byte[] publicAuthorityBytes = converter_.stringToByteArray(authority);
byte[] descriptionBytes = converter_.stringToByteArray(description);
byte[] replaceBytes = converter_.stringToByteArray(replace);
keyLength_ = keyLength;
queueType_ = queueType;
handle_ = impl_.create(objectNameBytes_, extendedAttributeBytes, queueType,
keyLength, dataSize_, initialNumberOfMessages,
additionalNumberOfMessages, publicAuthorityBytes, descriptionBytes,
replaceBytes);
}
/**
* Deletes the user queue.
*/
public void delete() {
impl_.delete(handle_, objectNameBytes_);
}
/**
* Dequeues the next entry from a FIFO or LIFO queue as a string
*
* @throws IllegalObjectTypeException
* @throws UnsupportedEncodingException
*/
public String dequeue() throws IllegalObjectTypeException,
UnsupportedEncodingException {
if (handle_ == 0) {
open();
}
if (queueType_ == QUEUE_TYPE_FIRST_IN_FIRST_OUT
|| queueType_ == QUEUE_TYPE_LAST_IN_FIRST_OUT) {
// Queue type is ok
} else {
Trace.log(Trace.ERROR, "Using dequeue for non FIFO / LIFO user queue.");
throw new IllegalObjectTypeException(
IllegalObjectTypeException.DATA_QUEUE_KEYED);
}
if (keyLength_ == 0) {
byte[] deqMsgPrefixBytes = new byte[20];
byte[] outputBytes = new byte[dataSize_];
int messageDequeued = impl_.dequeue(handle_, deqMsgPrefixBytes,
outputBytes);
if (messageDequeued == 0) {
return null;
} else {
int outputLength = (0xFF & deqMsgPrefixBytes[16]) * 256 * 16
+ (0xFF & deqMsgPrefixBytes[17]) * 256
+ (0xFF & deqMsgPrefixBytes[18]) * 16
+ (0xFF & deqMsgPrefixBytes[19]);
// This should work because we are running on IBM i, which
// supports IBM-037
return new String(outputBytes, 0, outputLength, "IBM-037");
}
} else {
Trace.log(Trace.ERROR, "Using dequeue for keyLength_ == 0.");
throw new IllegalObjectTypeException(
IllegalObjectTypeException.DATA_QUEUE_KEYED);
}
}
/**
* Dequeues an entry from the user queue.
*
* @param dequeueMessagePrefixBytes
* A Dequeue Message Prefix byte array used by the DEQI MI
* instruction. This provides both input and output information for
* the dequeue operation. The format of this byte array is as
* follows. For more information, see
* http://publib.boulder.ibm.com/infocenter
* /iseries/v7r1m0/index.jsp?topic=/rzatk/DEQ.htm.
*
*
* Offset
* Dec Hex Field Name Data Type and Length
* 0 0 Timestamp of enqueue of message Char(8) ++
* 8 8 Dequeue wait time-out value Char(8) +
* 16 10 Size of message dequeued Bin(4) ++
* 20 14 Access state modification option Char(1) +
* indicator and message selection
* criteria
* 21 15 Search key (ignored for FIFO/LIFO Char(key length) +
* queues but must be present for
* FIFO/LIFO queues with nonzero key
* length values)
* * Message key Char(key length) ++
*
* Note: Fields shown here with one plus sign (+) indicate input to the instruction,
* and fields shown here with two plus signs (++) are returned by the machine.
*
* @param outputBytes
* Byte array to receive the bytes contained in the queue entry.
* @return Returns 1 if a message was dequeued, 0 if a message was not
* dequeued.
* @throws AS400SecurityException
* If a security or authority error occurs.
* @throws ErrorCompletingRequestException
* If an error occurs before the request is completed.
* @throws IOException
* If an error occurs while communicating with the system.
* @throws IllegalObjectTypeException
* If the object on the system is not the required type.
* @throws InterruptedException
* If this thread is interrupted.
* @throws ObjectDoesNotExistException
* If the object does not exist on the system.
**/
public int dequeue(byte[] dequeueMessagePrefixBytes, byte[] outputBytes)
throws AS400SecurityException, ErrorCompletingRequestException,
IOException, IllegalObjectTypeException, InterruptedException,
ObjectDoesNotExistException {
if (handle_ == 0) {
open();
}
return impl_.dequeue(handle_, dequeueMessagePrefixBytes, outputBytes);
}
/**
* Returns the String representation of this user queue object.
*
* @return The String representation of this user queue object.
**/
public String toString() {
return "UserQueue " + path_;
}
/**
* Enqueues a string on the user queue
*
* @throws UnsupportedEncodingException
* @throws IllegalObjectTypeException
*/
public void enqueue(String value) throws UnsupportedEncodingException,
IllegalObjectTypeException {
byte[] valueBytes = converter_.stringToByteArray(value);
if (handle_ == 0) {
open();
}
if (queueType_ == QUEUE_TYPE_FIRST_IN_FIRST_OUT
|| queueType_ == QUEUE_TYPE_LAST_IN_FIRST_OUT) {
// Queue type is ok
} else {
Trace.log(Trace.ERROR, "Using dequeue for keyLength_ == 0.");
throw new IllegalObjectTypeException(
IllegalObjectTypeException.DATA_QUEUE_KEYED);
}
impl_.enqueue(handle_, null, valueBytes);
}
/**
* Enqueues an entry on the user queue using the ENQ MI instruction.
*
* @param enqueueMessagePrefixBytes
* A byte array representing the message prefix passed to the ENQ MI
* instruction. A value of null may be passed when using a FIFO to
* LIFO queue.
*
* The format of the message prefix is the following. For more
* information, see
* http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0
* /index.jsp?topic=/rzatk/ENQ.htm
*
*
* Offset
* Dec Hex Field Name Data Type and Length
* 0 0 Size of message to be enqueued Bin(4)
* 4 4 Enqueue key value (ignored for Char(key length)
* FIFO/LIFO queues with key
* lengths equal to 0)
*
*
* The static method {@link #setEnqueueMessagePrefixBytesMessageSize
* setEnqueueMessagePrefixBytesMessageSize()} can be used to set the
* size. The static method
* {@link #setEnqueueMessagePrefixBytesEnqueueKey
* setEnqueueMessagePrefixBytesEnqueueKey()} can be used to set the
* size.
* @param entryBytes
* A byte array representing the entry to add to the queue.
* @throws AS400SecurityException
* If a security or authority error occurs.
* @throws ErrorCompletingRequestException
* If an error occurs before the request is completed.
* @throws IOException
* If an error occurs while communicating with the system.
* @throws IllegalObjectTypeException
* If the object on the system is not the required type.
* @throws InterruptedException
* If this thread is interrupted.
* @throws ObjectDoesNotExistException
* If the object does not exist on the system.
**/
public void enqueue(byte[] enqueueMessagePrefixBytes, byte[] entryBytes)
throws Exception {
if (handle_ == 0) {
open();
}
if (enqueueMessagePrefixBytes == null) {
impl_.enqueue(handle_, null, entryBytes);
} else {
Trace.log(Trace.ERROR, "Keyed message queue not yet supported.");
throw new IllegalObjectTypeException(
IllegalObjectTypeException.DATA_QUEUE_KEYED);
}
}
/**
* Indicates if the native methods will be used internally to perform user
* queue dequeue and enqueue requests.
*
* @return true if user dequeue and enqueue requests will be performed via
* native methods; false otherwise.
* @see #setMustUseNativeMethods
**/
public boolean isMustUseNativeMethods() {
if (Trace.traceOn_)
Trace.log(Trace.DIAGNOSTIC,
"Checking if user queue must use native methods:",
mustUseNativeMethods_);
return mustUseNativeMethods_;
}
/**
* Specifies whether native methods are used by the current job to perform
* user queue operations. This option can only be set to true when the
* application is running on the System i.
*
* @param useNativeMethods
* Internally use native methods to perform read and write requests.
* @see #isMustUseNativeMethods
**/
public void setMustUseNativeMethods(boolean useNativeMethods) {
if (Trace.traceOn_)
Trace.log(Trace.DIAGNOSTIC,
"Setting if user queue must use native methods:", useNativeMethods);
if (useNativeMethods) {
if (!mustUseNativeMethods_) {
mustUseNativeMethods_ = useNativeMethods;
impl_ = new UserQueueImplILE(converter_);
}
} else {
if (mustUseNativeMethods_) {
mustUseNativeMethods_ = useNativeMethods;
if (impl_ != null) {
impl_.close(handle_);
impl_ = null;
handle_ = 0;
}
}
}
}
/*
* private methods
*/
private void open() {
handle_ = impl_.open(objectNameBytes_);
// TODO : Determine attributes.
byte[] outputBytes = new byte[128];
impl_.getAttributes(handle_, outputBytes);
//
// 96 60 Queue type Bits 1-2
// 00 = Keyed
// 01 = Last in, first out (LIFO)
// 10 = First in, first out (FIFO)
if ((outputBytes[96] & 0x60) == 0) {
queueType_ = QUEUE_TYPE_KEYED;
} else if ((outputBytes[96] & 0x60) == 0x20) {
queueType_ = QUEUE_TYPE_LAST_IN_FIRST_OUT;
} else if ((outputBytes[96] & 0x60) == 0x40) {
queueType_ = QUEUE_TYPE_FIRST_IN_FIRST_OUT;
}
// 111 6F Maximum size of message to be enqueued Bin(4)
dataSize_ = 0x1000000 * (0xFF & outputBytes[111]) + 0x10000
* (0xFF & outputBytes[112]) + 0x100 * (0xFF & outputBytes[113])
+ (0xFF & outputBytes[114]);
// 109 6D Key length Bin(2)
keyLength_ = 0x100 * (0xFF & outputBytes[109]) + (0xFF & outputBytes[110]);
}
/*
* Static methods for working with dequeue message prefix bytes.
*/
/**
* Resets the dequeueMessagePrefixBytes to zero
*/
public static void resetDequeueMessagePrefixBytes(
byte[] dequeueMessagePrefixBytes) {
Arrays.fill(dequeueMessagePrefixBytes, (byte) 0x0);
}
/**
* Returns the output length from the deqMsgPrefixBytes buffer
*/
public static int getDequeueMessagePrefixBytesLength(byte[] deqMsgPrefixBytes) {
return (0xFF & deqMsgPrefixBytes[16]) * 256 * 16
+ (0xFF & deqMsgPrefixBytes[17]) * 256 + (0xFF & deqMsgPrefixBytes[18])
* 16 + (0xFF & deqMsgPrefixBytes[19]);
}
/**
* Resets the enqueueMessagePrefixBytes to zero
*
* The format of the enqueueMessagePrefix is the following Offset Dec Hex
* Field Name Data Type and Length 0 0 Size of message to be enqueued Bin(4) 4
* 4 Enqueue key value Char(key length) (ignored for FIFO/LIFO queues with key
* lengths equal to 0)
*
*/
public static void resetEnqueueMessagePrefixBytes(
byte[] enqueueMessagePrefixBytes) {
Arrays.fill(enqueueMessagePrefixBytes, (byte) 0x0);
}
public static void setEnqueueMessagePrefixBytesMessageSize(
byte[] enqueueMessagePrefixBytes, int messageSize) {
enqueueMessagePrefixBytes[0] = (byte) (messageSize / 0x1000000);
enqueueMessagePrefixBytes[1] = (byte) ((messageSize / 0x10000) & 0xFF);
enqueueMessagePrefixBytes[2] = (byte) ((messageSize / 0x100) & 0xFF);
enqueueMessagePrefixBytes[3] = (byte) (messageSize & 0xFF);
}
public static void setEnqueueMessagePrefixBytesEnqueueKey(
byte[] enqueueMessagePrefixBytes, byte[] keyBytes) {
System
.arraycopy(keyBytes, 0, enqueueMessagePrefixBytes, 4, keyBytes.length);
}
}