com.ibm.as400.resource.SystemResourceList Maven / Gradle / Ivy
Show all versions of jt400 Show documentation
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: SystemResourceList.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-2000 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.resource;
import com.ibm.as400.access.AS400;
import com.ibm.as400.access.AS400Message;
import com.ibm.as400.access.Trace;
import com.ibm.as400.data.PcmlException;
import com.ibm.as400.data.ProgramCallDocument;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Hashtable;
/**
Retrieves list items using IBM i "Open List"
Application Programming Interfaces (APIs). This class is intended
to be extended and customized by subclasses.
@deprecated Use packages com.ibm.as400.access and com.ibm.as400.access.list instead.
**/
public class SystemResourceList
extends BufferedResourceList
{
static final long serialVersionUID = 4L;
// Private data.
private static final String closeProgramName_ = "qgyclst";
private static final String requestHandleDataNameSuffix_ = ".requestHandle";
private static final String closeRequestHandleDataName_ = "qgyclst.requestHandle";
private static final String getProgramName_ = "qgygtle";
private static final String getNumberOfRecordsToReturnDataName_ = "qgygtle.numberOfRecordsToReturn";
private static final String getRequestHandleDataName_ = "qgygtle.requestHandle";
private static final String getStartingRecordDataName_ = "qgygtle.startingRecord";
private static final String listInformationDataNameSuffix_ = ".listInformation";
private static final String listStatusIndicatorDataNameSuffix_ = ".listInformation.listStatusIndicator";
private static final String receiverVariableLengthDataName_ = "qgygtle.receiverVariableLength";
private static final String recordsReturnedDataNameSuffix_ = ".listInformation.recordsReturned";
private static final String requestHandleDataNameSuffix2_ = ".listInformation.requestHandle";
private static final String totalRecordsDataNameSuffix_ = ".listInformation.totalRecords";
private String formatName_ = null;
private String openListProgramName_ = null;
private ProgramMap selectionMap_ = null;
private Hashtable selectionBidiStringTypes_ = new Hashtable(); // @A2A
private transient ProgramCallDocument document_ = null;
private transient int formatLength_ = -1;
private transient byte[] requestHandle_ = null;
/**
Constructs a SystemResourceList object.
@param presentation The presentation, or null if not applicable.
@param attributes The attributes, or null if not applicable.
@param selections The selections, or null if not applicable.
@param sorts The sorts, or null if not applicable.
@param openListProgramName The open list program name.
@param formatName The format name for each item in the list,
or null if not needed.
@param selectionMap The program map which maps selection values in the
resource list to parameters in the PCML document,
or null if this should not be used.
**/
SystemResourceList(Presentation presentation,
ResourceMetaDataTable attributes,
ResourceMetaDataTable selections,
ResourceMetaDataTable sorts,
String openListProgramName,
String formatName,
ProgramMap selectionMap)
{
super(presentation, attributes, selections, sorts);
initializeTransient();
if (openListProgramName == null)
throw new NullPointerException("openListProgramName");
openListProgramName_ = openListProgramName;
formatName_ = formatName;
selectionMap_ = selectionMap;
}
/**
Closes the list. No further resources can be loaded. The list
must be closed in order to clean up resources appropriately.
This method has no effect if the list is already closed.
This method fires a listClosed() ResourceListEvent.
@exception ResourceException If an error occurs.
**/
public void close()
throws ResourceException
{
if (!isOpen())
return;
super.close();
fireBusy();
try {
// Close the list by calling the close list API.
if ((document_ != null) && (requestHandle_ != null)) {
document_.setValue(closeRequestHandleDataName_, requestHandle_);
if (document_.callProgram(closeProgramName_) == false)
throw new ResourceException(document_.getMessageList(closeProgramName_));
}
}
catch (ResourceException e) {
AS400Message[] msgList = e.getMessageList();
if (msgList != null && msgList.length > 0 &&
msgList[0].getID().equals("GUI0001")) // "Invalid handle specified"
{
// Tolerate the error, and continue.
// Note that it's already been traced by the exception ctor.
}
else throw e; // rethrow it
}
catch(PcmlException e) {
throw new ResourceException(e);
}
finally {
// Done with the request handle.
requestHandle_ = null; // Ensure we don't try to keep using this handle.
fireIdle();
}
}
/**
Returns the PCML document.
@return The PCML document.
**/
ProgramCallDocument getDocument()
{
return document_;
}
/**
Initializes the transient data.
**/
private void initializeTransient()
{
formatLength_ = -1;
}
// @A2A
/**
Indicates if this resource is enabled for bidirectional character conversion.
This always returns true.
@return Always true.
**/
protected boolean isBidiEnabled()
{
return true;
}
/**
Indicates if the resource is available. This means that the
resource has been loaded.
@param index The index.
@return true if the resource is available,
false if the resource is not available
or the list is not open.
@exception ResourceException If an error occurs.
**/
public boolean isResourceAvailable(long index)
throws ResourceException
{
// First check to see if the resource is already buffered in the superclass.
boolean isAvailable = super.isResourceAvailable(index);
// If not... and if the list is open...
if ((! isAvailable) && (isOpen())) {
// Refresh the status, which will include the current list length.
loadResources(0, 0);
// If this index is less than the length, then its available.
isAvailable = (index < getListLength());
}
return isAvailable;
}
/**
Loads a part of the list.
@param startIndex The start index (1-based). If this is 0,
then immediately refresh the list status.
If this is -1, then wait for the entire
list to complete. If this is greater than
0, then wait for the indexed list item
to be built.
@param length The number of resources to load. If this
is 0, then refresh only the list status.
@exception ResourceException If an error occurs.
**/
private void loadResources(long startIndex, long length)
throws ResourceException
{
if (Trace.isTraceOn())
Trace.log(Trace.INFORMATION, "Loading resources (" + startIndex + ", " + length + ") from list " + this + ".");
fireBusy();
try {
// Set the receiver variable length. This only needs
// to be set if a format name was provided in the constructor.
// Otherwise, we will assume its been initialized in the
// PCML.
if (formatName_ != null) {
if (formatLength_ == -1)
formatLength_ = document_.getOutputsize(formatName_);
if (length == 0)
document_.setIntValue(receiverVariableLengthDataName_, 1); // 0 causes problems.
else
document_.setIntValue(receiverVariableLengthDataName_, (int)length*formatLength_);
}
// Set some other API parameters.
document_.setValue(getRequestHandleDataName_, requestHandle_);
document_.setIntValue(getNumberOfRecordsToReturnDataName_, (int)length);
document_.setIntValue(getStartingRecordDataName_, (int)startIndex);
// Call the API.
if (document_.callProgram(getProgramName_) == false)
throw new ResourceException(document_.getMessageList(getProgramName_));
// Process the returned information.
process(getProgramName_, startIndex - 1); // process() is 0-based.
}
catch(PcmlException e) {
throw new ResourceException(e);
}
finally {
fireIdle();
}
}
/**
Creates and returns a new resource based on a record returned
from an API call. A subclass must implement this method.
@param programName The program name.
@param indices The indices. These indicate which record
to use.
@return The new resource.
@exception PcmlException If a PCML error occurs.
@exception ResourceException If an error occurs.
**/
Resource newResource(String programName,
int[] indices)
throws PcmlException, ResourceException
{
throw new ResourceException();
}
/**
Opens the list. The list must be open in order to
perform most operations. This method has no effect
if the list is already opened.
@exception ResourceException If an error occurs.
**/
public void open()
throws ResourceException
{
if (isOpen())
return;
super.open();
fireBusy();
try {
synchronized(this) {
// Establish the connection if needed.
if (! isConnectionEstablished())
establishConnection();
try {
// Set the open parameters.
setOpenParameters(document_);
// Call the program.
boolean success = document_.callProgram(openListProgramName_);
if (!success)
throw new ResourceException(document_.getMessageList(openListProgramName_));
requestHandle_ = (byte[])document_.getValue(openListProgramName_ + requestHandleDataNameSuffix2_);
process(openListProgramName_, 0);
}
catch(Exception e) {
// We will mostly catch PcmlExceptions here, but there will be
// occasion when IllegalArguementExceptions are thrown by the
// text conversion classes.
throw new ResourceException(e);
}
}
}
finally {
fireIdle();
}
}
/**
Process information returned from either the open or get APIs. This method
will take that information and create new Resources for it.
@param programName The program name.
@param startIndex The start index (0-based).
@exception PcmlException If a PCML error occurs.
@exception ResourceException If an error occurs.
**/
private void process(String programName, long startIndex)
throws PcmlException, ResourceException
{
// For each record that was returned...
int recordsReturned = document_.getIntValue(programName + recordsReturnedDataNameSuffix_);
for(int i = 0; i < recordsReturned; ++i) {
int[] indices = { i };
// Manufacture a new resource.
Resource resource = newResource(programName, indices);
// Notify listeners.
fireResourceAdded(resource, startIndex + i);
}
// Fire any other necessary events.
String listStatusIndicator = (String)document_.getValue(programName + listStatusIndicatorDataNameSuffix_);
long newLength = document_.getIntValue(programName + totalRecordsDataNameSuffix_);
if (Trace.isTraceOn()) {
Trace.log(Trace.INFORMATION, "API List status indicator = " + listStatusIndicator);
Trace.log(Trace.INFORMATION, "API List length = " + newLength);
}
if (listStatusIndicator.equals("2"))
fireListCompleted();
else if (listStatusIndicator.equals("3"))
fireListInError();
if (newLength != getListLength())
fireLengthChanged(newLength);
}
/**
Deserializes the resource list.
**/
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
initializeTransient ();
}
/**
Refreshes the contents of the list.
This will implicitly open the list if needed.
@exception ResourceException If an error occurs.
**/
public void refreshContents()
throws ResourceException
{
// Establish the connection if needed.
if (! isConnectionEstablished())
establishConnection();
// Close to force a re-open.
if (isOpen())
close();
super.refreshContents();
}
/**
Refreshes the status of the list. The status includes
the length and whether the list is completed or in error.
If the list is complete, this method has no effect.
This method does not refresh the contents of the list. Use
{@link #refreshContents refreshContents()} to refresh
the contents of the list.
This will implicitly open the list if needed.
@exception ResourceException If an error occurs.
**/
public void refreshStatus()
throws ResourceException
{
super.refreshStatus();
loadResources(0, 0);
}
/**
Returns the resource specified by the index.
This will implicitly open the list if needed.
@param index The index.
@return The resource specified by the index, or null
if the resource is not yet available.
@exception ResourceException If an error occurs.
**/
public Resource resourceAt(long index)
throws ResourceException
{
synchronized(this) {
// It may already be here.
Resource resource = super.resourceAt(index);
// If not, try to load it.
if (resource == null) {
loadResources(index + 1, getPageSize()); // loadResources() is 1-based
resource = super.resourceAt(index);
// If the resource is STILL null, it means that the buffer
// swapped out the resource during loading. This happens
// only when the number of pages is 1. The simplest
// workaround is to reload the single resource.
if (resource == null) {
if (Trace.isTraceOn())
Trace.log(Trace.INFORMATION, "Double load scenario, index=" + index +
", number of pages= " + getNumberOfPages() + ", page size="
+ getPageSize());
loadResources(index + 1, getPageSize()); // loadResource() is 1-based
resource = super.resourceAt(index);
}
}
return resource;
}
}
/**
Sets the parameters for the open API. This uses the selection map
to copy selection values from the resource list to the parameters
in the PCML document.
If different settings are needed, then override this method.
@param document The document.
@exception PcmlException If a PCML error occurs.
@exception ResourceException If a Resource error occurs.
**/
void setOpenParameters(ProgramCallDocument document)
throws PcmlException, ResourceException
{
if (selectionMap_ != null) {
// Copy the selection values from the resource list to the
// parameters in the PCML document.
ResourceMetaData[] selectionMetaData = getSelectionMetaData();
Object[] ids = new Object[selectionMetaData.length];
Object[] values = new Object[selectionMetaData.length];
int[] bidiStringTypes = new int[selectionMetaData.length]; // @A2A
for(int i = 0; i < selectionMetaData.length; ++i) {
ids[i] = selectionMetaData[i].getID();
values[i] = getSelectionValue(ids[i]);
Integer selectionBidiStringType = (Integer)selectionBidiStringTypes_.get(ids[i]); // @A2A
if (selectionBidiStringType == null) // @A2A
bidiStringTypes[i] = getDefaultBidiStringType(); // @A2A
else // @A2A
bidiStringTypes[i] = selectionBidiStringType.intValue(); // @A2A
}
selectionMap_.setValues(ids, values, getSystem(), document, openListProgramName_, null, bidiStringTypes); // @A2C
}
}
/**
Sets the PCML document.
@param document The PCML document.
**/
void setDocument(ProgramCallDocument document)
{
if (document == null)
throw new NullPointerException("document");
document_ = document;
AS400 system = getSystem();
if (system != null)
document_.setSystem(system);
}
void setOpenListProgramName(String openListProgramName)
{
if (openListProgramName == null)
throw new NullPointerException("openListProgramName");
openListProgramName_ = openListProgramName;
}
// @A2A
/**
Sets the current value of a selection. The changed selection
value will take effect the next time the list is opened
or refreshed.
@param selectionID Identifies the selection.
@param value The selection value, or null to remove
the selection.
@param bidiStringType The bidi string type as defined by the CDRA (Character Data
Representation Architecture). See
{@link com.ibm.as400.access.BidiStringType BidiStringType}
for more information and valid values.
@exception ResourceException If an error occurs.
**/
public void setSelectionValue(Object selectionID, Object value, int bidiStringType)
throws ResourceException
{
super.setSelectionValue(selectionID, value, bidiStringType);
selectionBidiStringTypes_.put(selectionID, Integer.valueOf(bidiStringType));
}
/**
Waits until the list is completely loaded.
This will implicitly open the list if needed.
@exception ResourceException If an error occurs.
**/
public void waitForComplete()
throws ResourceException
{
super.waitForComplete();
if (!isComplete())
loadResources(-1, 0);
}
/**
Waits until the resource is available or the list is
complete.
This will implicitly open the list if needed.
@param index The index.
@exception ResourceException If an error occurs.
**/
public void waitForResource(long index)
throws ResourceException
{
super.waitForResource(index);
if (isComplete())
return;
if (!isResourceAvailable(index))
loadResources(index + 1, 0); // loadResource() is 1-based
}
}