src.com.ibm.as400.access.ClientAccessDataStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jt400-jdk9 Show documentation
Show all versions of jt400-jdk9 Show documentation
The Open Source version of the IBM Toolbox for Java
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: ClientAccessDataStream.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) 1997-2001 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.access;
import java.io.IOException;
import java.io.InputStream;
import java.util.Hashtable;
/** Base class for client access server data streams.
* Provides methods to access common client access data stream header.
*
*/
public class ClientAccessDataStream extends DataStream
{
static final String copyright = "Copyright (C) 1997-2001 International Business Machines Corporation and others.";
protected static final int HEADER_LENGTH = 20;
private static final CADSPool basePool_ = new CADSPool(); //@P0A - base datastream pool
private class InUseLock extends Object {} //@C7A
private InUseLock inUseLock_ = new InUseLock();
// Note: All references to inUse_ in subclass should be followed by
// a call to canUse, which which acquire the lock to validate that
// the DataStream can actually be used.
boolean inUse_; //@P0A
private CADSPool fromPool_ = null;
private int fromPoolIndex_ = 0;
// Note: The following method is called by AS400ThreadedServer and AS400NoThreadServer.
// Construct an appropriate client access data stream object. Read from the InputStream to obtain the data stream data for the object.
// @param is InputStream from which to read to obtain the data stream contents.
// @param dataStreams Hashtable containing instances of data stream objects to receive into. This table is searched first when a reply comes in. If found the datastream will be removed from here as it is received.
// @param dataStreams Prototypes Hashtable containing data stream objects from which to obtain a model for this object.
// @exception IOException Data read from the input stream is less than 20 bytes or we are unable to read from the input stream for some other reason.
// @return ClientAccessDataStream object.
static final ClientAccessDataStream construct(InputStream is, Hashtable dataStreams, Hashtable dataStreamPrototypes, AS400ImplRemote system, int connectionID) throws IOException
{
// Construct a client access data stream to receive the data stream header. By using the default constructor for ClientAccessDataStream, we get a data stream of size HEADER_LENGTH.
//@P0D ClientAccessDataStream baseDataStream = new ClientAccessDataStream();
ClientAccessDataStream baseDataStream = basePool_.getUnusedStream(); //@P0A
try
{
// Receive the header.
byte[] data = baseDataStream.data_;
if (readFromStream(is, data, 0, HEADER_LENGTH, connectionID) < HEADER_LENGTH)
{
if (Trace.traceOn_) Trace.log(Trace.ERROR, "Failed to read all of the data stream header."); //@P0C
baseDataStream.returnToPool(); baseDataStream=null;
throw new ConnectionDroppedException(ConnectionDroppedException.CONNECTION_DROPPED);
}
// int length2 = ((data[0] & 0xFF) << 24) + ((data[1] & 0xFF) << 16) + ((data[2] & 0xFF) << 8) + (data[3] & 0xFF);
int length = baseDataStream.getLength();
if (baseDataStream.data_[6] != (byte)0xE0)
{
// boolean traceTurnedOn = false;
// if (!Trace.traceOn_) {
// traceTurnedOn = true;
// }
// Debugging code.
// if (! DataStream.traceOpened) {
// SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmm");
// Trace.setFileName("/tmp/toolboxTrace."+sdf.format(new Date())+".txt");
// DataStream.traceOpened=true;
// }
// if (!Trace.traceOn_) {
// traceTurnedOn = true;
// Trace.setTraceAllOn(true);
// Trace.setTraceOn(true);
// }
// Trace.log(Trace.ERROR, "Debug0601: Incorrect data stream header detected. baseDataStream.data_("+baseDataStream.data_.toString()+") length=("+length+")",
// baseDataStream.data_, 0, HEADER_LENGTH);
// Trace.log(Trace.ERROR, "Debug0601: Incorrect data stream header detected. data_("+data.toString()+") length=("+length2+")",
// data, 0, HEADER_LENGTH);
if (Trace.traceOn_) {
Trace.log(Trace.ERROR, "Incorrect data stream header detected.",
baseDataStream.data_, 0, HEADER_LENGTH);
}
// Debugging code
//if (traceTurnedOn) {
// Trace.setTraceAllOn(false);
// Trace.setTraceOn(false);
//}
baseDataStream.returnToPool(); baseDataStream=null;
is.skip(is.available()); // disregard the rest of this data stream
// Debug...
// Just hang the thread
// while (true) {
// try {
// Thread.sleep(100000);
// } catch (Exception e) {
// break;
// }
//}
throw new InternalErrorException(InternalErrorException.DATA_STREAM_UNKNOWN);
}
// First look for an instance data stream.
// If we found it remove it since instance datastreams are only used once.
// Print is the only thing that uses this.
ClientAccessDataStream newDataStream = (ClientAccessDataStream)dataStreams.get(baseDataStream);
if(newDataStream != null && newDataStream instanceof NPDataStream)
{
NPDataStream npds = (NPDataStream)newDataStream;
if(baseDataStream.getCorrelation() == npds.getCorrelationID())
dataStreams.remove(baseDataStream);
}
if(newDataStream != null && !(newDataStream instanceof NPDataStream))
{
newDataStream = (ClientAccessDataStream)dataStreams.remove(baseDataStream);
}
if (newDataStream == null) //@P0C
{
// If we couldn't find an instance datastream to receive into, look for a prototype data stream to generate one with.
ClientAccessDataStream modelDataStream = (ClientAccessDataStream)dataStreamPrototypes.get(baseDataStream);
if (modelDataStream == null)
{
// No model was found in the hash table, so we will return a generic data stream.
newDataStream = new ClientAccessDataStream();
}
else
{
// Get a new instance of the data stream.
newDataStream = (ClientAccessDataStream)modelDataStream.getNewDataStream();
if (newDataStream == null)
{
newDataStream = new ClientAccessDataStream();
}
}
}
newDataStream.system_ = system;
if (Trace.traceOn_) newDataStream.setConnectionID(connectionID);
// Initialize the header section of the new data stream.
int nowLength = baseDataStream.getLength();
// Debugging code
// if ((nowLength != length) || (length != length2) || (data != baseDataStream.data_ )) {
// if (! DataStream.traceOpened) {
// SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmm");
//
// Trace.setFileName("/tmp/toolboxTrace."+sdf.format(new Date())+".txt");
// DataStream.traceOpened=true;
// }
//
// boolean traceTurnedOn = false;
// if (!Trace.traceOn_) {
// traceTurnedOn = true;
// Trace.setTraceAllOn(true);
// Trace.setTraceOn(true);
// }
// if (nowLength != length) {
// Trace.log(Trace.DATASTREAM, "Debug0601: Buffer corrupted.. Original length="+length+" nowLength="+nowLength);
// }
// if (length != length2) {
// Trace.log(Trace.DATASTREAM, "Debug0601: Buffer corrupted.. Original length="+length+" length2="+length2);
// }
// if (data != baseDataStream.data_) {
// Trace.log(Trace.DATASTREAM, "Debug0601: Buffer corrupted.. data="+data+" baseDataStream.data_="+baseDataStream.data_);
// }
// if (traceTurnedOn) {
// Trace.setTraceAllOn(false);
// Trace.setTraceOn(false);
// }
//}
//
// TODO: Restructure this code so that a new byte array is not always allocated.
//
newDataStream.data_ = new byte[nowLength];
System.arraycopy(baseDataStream.data_, 0, newDataStream.data_, 0, HEADER_LENGTH);
if (newDataStream.data_.length - HEADER_LENGTH > 0)
{
// Receive any remaining bytes.
// The number of bytes to read is calculated from newDataStream.data_.length - HEADER_LENGTH
newDataStream.readAfterHeader(is);
}
return newDataStream;
}
finally
{
if (baseDataStream != null) {
baseDataStream.returnToPool(); baseDataStream = null;
}
}
}
// Constructs an empty ClientAccessDataStream object.
protected ClientAccessDataStream()
{
super(HEADER_LENGTH);
}
// Constructs a ClientAccessDataStream object.
// @param data Byte array with which to initialize this data stream.
ClientAccessDataStream(byte[] ds)
{
super(HEADER_LENGTH, ds);
}
// Constructs an empty ClientAccessDataStream object that is pooled.
ClientAccessDataStream(CADSPool pool, int poolIndex) {
super(HEADER_LENGTH);
fromPool_ = pool;
fromPoolIndex_ = poolIndex;
}
// Retrieve the request correlation for this data stream. The return value may be invalid if it has not been set.
// @return The request correlation number.
int getCorrelation()
{
return get32bit(12);
}
// Retrieve the CS instance for the data stream. The return value may be invalid if it has not been set.
// @return The CS instance of the data stream.
int getCSInstance()
{
return get32bit(8);
}
// Retrieve the header ID for the data stream. The return value may be invalid if it has not been set.
// @return The ID of the data stream.
int getHeaderID()
{
return get16bit(4);
}
// Retrieve the total length of the data stream. The return value may be invalid if it has not been set.
// @return The total length of this data stream.
int getLength()
{
return get32bit(0);
}
// Retrieve the request/reply ID of the data stream. The return value may be invalid if it has not been set.
// @return The request/reply ID of this data stream.
int getReqRepID()
{
//@P0D return get16bit(18);
return((data_[18] & 0xFF) << 8) + (data_[19] & 0xFF); //@P0A
}
// Retrieve the server ID of the data stream. The return value may be invalid if it has not been set.
// @return The server ID of this data stream.
int getServerID()
{
return get16bit(6);
}
// Retrieve the template length of the data stream. The return value may be invalid if it has not been set.
// @return The template length of this data stream.
int getTemplateLen()
{
return get16bit(16);
}
// Retrieve the hash code of the data stream. The return value may be invalid if it has not been set.
// Note: Reply data stream sub-classes should override this method to return the request/reply id directly instead of calling getReqRepId().
// @return The hash code of this data stream.
public int hashCode()
{
//@P0D return getReqRepID();
return((data_[18] & 0xFF) << 8) + (data_[19] & 0xFF); //@P0A
}
// Set the request correlation for this data stream.
// @param id The request correlation number.
protected void setCorrelation(int id)
{
set32bit(id, 12);
}
// Set the CS instance for this data stream.
// @param id The CS instance.
protected void setCSInstance(int id)
{
set32bit(id, 8);
}
// Set the header ID for the data stream. It should be set to 0 for most of the Client Access servers.
// @param id The header ID to set.
protected void setHeaderID(int id)
{
set16bit(id, 4);
}
// Set the length of the data stream. This is the total length of the data stream.
// @param len The length of the data stream.
protected void setLength(int len)
{
//@P0D set32bit(len, 0);
data_[0] = (byte)(len >>> 24);
data_[1] = (byte)(len >>> 16);
data_[2] = (byte)(len >>> 8);
data_[3] = (byte) len;
}
// Set the request/reply ID for the data stream.
// @param id The request/reply ID to set.
protected void setReqRepID(int id)
{
set16bit(id, 18);
}
// Set the server ID for the data stream. This is the ID of the server to talk to.
// @param id The ID of the server.
protected void setServerID(int id)
{
set16bit(id, 6);
}
// Set the template length for the data stream.
// @param len The template length.
protected void setTemplateLen(int len)
{
set16bit(len, 16);
}
//
// Indicate that the buffer can be returned to the pool. In the past, the pooling implementation
// just set inUse_=false to return to the pool. This is provided so that the request buffer can be resized
// by inheriting classes
//
void returnToPool() throws InternalErrorException { // @A7C
synchronized(inUseLock_) {
if (inUse_) {
// Use this to find places where the object is used after it is returned to the pool
// Note: For DBBaseRequestDS objects, the data_ pointer has been set to the one for the
// DBStorage object.
// if (data_ != null) {
// Arrays.fill(data_, (byte) 0xeb);
// }
inUse_ = false;
// if (DBDSPool.monitor && this instanceof DBReplyRequestedDS) {
// System.out.println("Freeing "+((DBReplyRequestedDS) this).poolIndex);
// }
} else {
// This is an error case. You cannot double free a buffer
throw new InternalErrorException(InternalErrorException.UNKNOWN);
}
}
// Let the pool know that something was returned. This should speed up searches through the pool.
if (fromPool_ != null) {
fromPool_.returnToPool(this, fromPoolIndex_);
}
}
/**
* Can this be used. If not, false is returned.
* If it can be used, then inUse_ is set to return and true is returned
* @return true if this can be used
*/
public boolean canUse() {
synchronized (inUseLock_) {
if (inUse_) {
return false;
} else {
inUse_ = true;
return true;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy