src.com.ibm.as400.access.RemoteCommandImplNative 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: RemoteCommandImplNative.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) 1999-2007 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
//
// @A1 - 9/18/2007 - Changes to follow proxy command chain.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.access;
import java.io.IOException;
// The RemoteCommandImplNative class is the native implementation of CommandCall and ProgramCall.
class RemoteCommandImplNative extends RemoteCommandImplRemote
{
private static final String CLASSNAME = "com.ibm.as400.access.RemoteCommandImplNative";
static
{
if (Trace.traceOn_) Trace.logLoadPath(CLASSNAME);
}
static
{
NativeMethods.loadNativeLibraryQyjspart();
}
// Report whether the RemoteCommandImpl object is a native object.
public boolean isNative()
{
return true;
}
// Connects to the server.
// @param threadSafety The assumed thread safety of the command/program.
protected void open(Boolean threadSafety) throws AS400SecurityException, ErrorCompletingRequestException, IOException, InterruptedException
{
// Note: LOOKUP_THREADSAFETY is null so == must be used
if ((LOOKUP_THREADSAFETY == threadSafety) || OFF_THREAD.equals(threadSafety)) {
openOffThread();
}
else {
openOnThread();
}
}
protected void openOnThread() throws AS400SecurityException, ErrorCompletingRequestException, IOException, InterruptedException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Native implementation object open.");
// If converter was not set with a user override ccsid, set converter to job ccsid.
if (!ccsidIsUserOveride_ && (converter_ == null))
{
converter_ = ConverterImplRemote.getConverter(system_.getCcsid(), system_);
}
if (AS400.nativeVRM.vrm_ >= 0x00050300)
{
if (AS400.nativeVRM.vrm_ >= 0x00060100)
{
serverDataStreamLevel_ = 10;
if (unicodeConverter_ == null) {
unicodeConverter_ = ConverterImplRemote.getConverter(1200, system_);
}
}
else
{
serverDataStreamLevel_ = 7;
}
}
// Set the secondary language library on the server.
if (system_.isMustAddLanguageLibrary() &&
!system_.isSkipFurtherSettingOfLanguageLibrary()) // see if we should try
{
// Note: If we were going through the Remote Command Host Server, the host server would set the secondary language library for us.
// Since we're not using the host server, we need to handle this ourselves.
// We need to do this on every open, since several different threads may be using this RemoteCommandImpl object.
// Retrieve the name of the secondary language library (if any).
String secLibName = retrieveSecondaryLanguageLibName(); // never returns null
// Set the NLV on server to match the client's locale.
if (secLibName.length() != 0)
{
setNlvOnServer(secLibName);
}
// Retain result, to avoid repeated library lookups for same system object.
system_.setLanguageLibrary(secLibName);
// Set to non-null, to indicate we already looked-up the value.
}
}
// Retrieves the secondary language library (if any).
// If fail to retrieve library name, or name is blank, returns "".
private String retrieveSecondaryLanguageLibName()
{
String secLibName = system_.getLanguageLibrary();
if (secLibName == null) // 'null' implies not already looked-up
{
String clientNLV = system_.getNLV(); // NLV of client (based on locale)
try
{
int ccsid = system_.getCcsid();
ConvTable conv = ConvTable.getTable(ccsid, null);
ProgramParameter[] parameterList = new ProgramParameter[6];
int len = 108+10; // length of PRDR0100, plus first 10 bytes of PRDR0200
parameterList[0] = new ProgramParameter(len); // receiver variable - PRDR0100 plus first 10 bytes of PRDR0200
parameterList[1] = new ProgramParameter(BinaryConverter.intToByteArray(len)); // length of receiver variable
parameterList[2] = new ProgramParameter(conv.stringToByteArray("PRDR0200")); // format name
byte[] productInfo = new byte[36]; // product information
AS400Text text4 = new AS400Text(4, ccsid, system_);
AS400Text text6 = new AS400Text(6, ccsid, system_);
AS400Text text7 = new AS400Text(7, ccsid, system_);
AS400Text text10 = new AS400Text(10, ccsid, system_);
text7.toBytes("*OPSYS", productInfo, 0); // product ID
text6.toBytes("*CUR", productInfo, 7); // release level
text4.toBytes("0000", productInfo, 13); // product option
text10.toBytes(clientNLV, productInfo, 17); // load ID (specifies desired NLV)
BinaryConverter.intToByteArray(36, productInfo, 28); // length of product information parm
BinaryConverter.intToByteArray(ccsid, productInfo, 32); // ccsid for returned directory
parameterList[3] = new ProgramParameter(productInfo); // product information
parameterList[4] = new ProgramParameter(new byte[4]); // error code
parameterList[5] = new ProgramParameter(conv.stringToByteArray("PRDI0200")); // product information format name
// Call QSZRTVPR (Retrieve Product Information) to retrieve the library for the secondary language.
// Note: QSZRTVPR is documented as non-threadsafe. However, the API owner has indicated that this API will never alter the state of the system, and that it cannot damage the system; so it can safely be called on-thread.
boolean succeeded = runProgramOnThread("QSYS", "QSZRTVPR", parameterList, AS400Message.MESSAGE_OPTION_UP_TO_10, true);
// Note: This method is only called from within open().
// The final parm indicates that the on-thread open() has already been done (on this thread).
if (!succeeded)
{
Trace.log(Trace.WARNING, "Unable to retrieve secondary language library name for NLV " + clientNLV, new AS400Exception(messageList_));
}
else
{
byte[] outputData = parameterList[0].getOutputData();
int offsetToAddlInfo = BinaryConverter.byteArrayToInt(outputData, 84);
secLibName = conv.byteArrayToString(outputData, offsetToAddlInfo, 10).trim();
if (secLibName.length() == 0) {
Trace.log(Trace.WARNING, "Unable to retrieve secondary language library name for NLV " + clientNLV + ": Blank library name returned.");
}
}
}
catch (Throwable t) {
Trace.log(Trace.WARNING, "Unable to retrieve secondary language library name for NLV " + clientNLV, t);
}
}
return (secLibName == null ? "" : secLibName);
}
// Sets the NLV (for the current thread) on the server, so that system msgs are returned in correct language.
private void setNlvOnServer(String secondaryLibraryName)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Native implementation object setting national language for messages.");
try
{
// Call CHGSYSLIBL (Change System Library List) to add the library for the secondary language.
// Note: According to the spec, CHGSYSLIBL "changes the system portion of the library list for the current thread".
// Prior to V6R1, CHGSYSLIBL is documented as non-threadsafe. However, the CL owner has indicated that this CL has actually been threadsafe all along, and that it cannot damage the system; so it can safely be called on-thread.
// At worst, if system value QMLTTHDACN == 3, the system will simply refuse to execute the command. In which case, the secondary language library won't get added.
String cmd = "QSYS/CHGSYSLIBL LIB("+secondaryLibraryName+") OPTION(*ADD)";
boolean succeeded = runCommandOnThread(cmd, AS400Message.MESSAGE_OPTION_UP_TO_10, true);
// Note: This method is only called from within open().
// The final parm indicates that the on-thread open() has already been done (on this thread).
if (!succeeded)
{
if (messageList_.length !=0)
{
if (messageList_[0].getID().equals("CPF2103")) // lib is already in list
{
// Tolerate this error. It means that we're good to go.
// If this is the very first native open() for this system_, set flag to indicate that the lib is already in list by default. This will eliminate clutter in the job log, from subsequent attempts to set it.
if (system_.getLanguageLibrary() == null) { // null implies first native open
system_.setSkipFurtherSettingOfLanguageLibrary(); // don't keep trying on subsequent open's
}
}
else if (messageList_[0].getID().equals("CPD0032")) // not auth'd to call CHGSYSLIBL
{
system_.setSkipFurtherSettingOfLanguageLibrary(); // don't keep trying on subsequent open's
Trace.log(Trace.DIAGNOSTIC, "Profile " + system_.getUserId() + " not authorized to use CHGSYSLIBL to add secondary language library " + secondaryLibraryName + " to liblist.");
// Note: The Remote Command Host Server runs this command under greater authority.
}
else if (messageList_[0].getID().equals("CPF2110")) // library not found
{
system_.setSkipFurtherSettingOfLanguageLibrary(); // don't keep trying on subsequent open's
Trace.log(Trace.WARNING, "Secondary language library " + secondaryLibraryName + " was not found.");
}
else
{
Trace.log(Trace.ERROR, "Unable to add secondary language library " + secondaryLibraryName + " to library list.", new AS400Exception(messageList_));
}
}
else // no system messages returned
{
Trace.log(Trace.WARNING, "Unable to add secondary language library " + secondaryLibraryName + " to library list.");
}
}
}
catch (Throwable t)
{
Trace.log(Trace.WARNING, "Failed to add secondary language library " + secondaryLibraryName + " to library list.", t);
}
}
//For native and thread safe, it gets the jvm job info. Otherwise, get the job info of host server.
public String getJobInfo(Boolean threadSafety) throws AS400SecurityException, ErrorCompletingRequestException, IOException, InterruptedException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting job information from implementation object.");
// Note: The runProgram() method that we call below, will call the appropriate open() method.
// Set up the parameter list for the program that we will use to get the job information (QWCRTVCA).
ProgramParameter[] parameterList = new ProgramParameter[6];
// First parameter: receiver variable - output - char(*).
// RTVC0100's 20-byte header, plus 26 bytes for "job name" field.
byte[] dataReceived = new byte[46];
parameterList[0] = new ProgramParameter(dataReceived.length);
// Second parameter: length of receiver variable - input - binary(4).
byte[] receiverLength = BinaryConverter.intToByteArray(dataReceived.length);
parameterList[1] = new ProgramParameter(receiverLength);
// Third parameter: format name - input - char(8).
// Set to EBCDIC "RTVC0100".
byte[] formatName = {(byte)0xD9, (byte)0xE3, (byte)0xE5, (byte)0xC3, (byte)0xF0, (byte)0xF1, (byte)0xF0, (byte)0xF0};
parameterList[2] = new ProgramParameter(formatName);
// Fourth parameter: number of attributes to return - input - binary(4).
byte[] numAttributes = BinaryConverter.intToByteArray(1); // 1 attribute.
parameterList[3] = new ProgramParameter(numAttributes);
// Fifth parameter: key of attributes to be returned - input - array(*) of binary(4).
byte[] attributeKey = BinaryConverter.intToByteArray(1009); // "Job name."
parameterList[4] = new ProgramParameter(attributeKey);
// Sixth parameter: error code - input/output - char(*).
// Eight bytes of zero's indicates to throw exceptions.
// Send as input because we are not interested in the output.
parameterList[5] = new ProgramParameter(new byte[8]);
// Prepare to call the "Retrieve Current Attributes" API.
// Design note: QWCRTVCA is documented to be conditionally threadsafe.
// Note: Depending upon whether the program represented by this ProgramCall object will be run on-thread or through the host servers (as indicated by the 'threadsafety' flag), we will issue the job info query accordingly, either on-thread or through the host servers, in order to get the appropriate Job.
// Retrieve Current Attributes. Failure is returned as a message list.
try
{
boolean succeeded;
if (ON_THREAD.equals(threadSafety)) {
succeeded = runProgramOnThread("QSYS", "QWCRTVCA", parameterList, MESSAGE_OPTION_DEFAULT, false);
}
else {
succeeded = runProgramOffThread("QSYS", "QWCRTVCA", parameterList, MESSAGE_OPTION_DEFAULT);
}
if (!succeeded)
{
Trace.log(Trace.ERROR, "Unable to retrieve job information.");
throw new AS400Exception(messageList_);
}
}
catch (ObjectDoesNotExistException e)
{
Trace.log(Trace.ERROR, "Unexpected ObjectDoesNotExistException:", e);
throw new InternalErrorException(InternalErrorException.UNEXPECTED_EXCEPTION);
}
// Get the data returned from the program.
dataReceived = parameterList[0].getOutputData();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Job information retrieved:", dataReceived);
// Examine the "job name" field. 26 bytes starting at offset 20. The format of the job name is a 10-character simple job name, a 10-character user name, and a 6-character job number.
return converter_.byteArrayToString(dataReceived, 20, 26);
}
// This method is reserved for use by other Impl classes in this package.
public boolean runCommand(String command) throws AS400SecurityException, ErrorCompletingRequestException, IOException, InterruptedException
{
// The caller didn't specify whether to call the command on- or off-thread.
// Base the decision on the setting the "threadSafe" system property.
if (shouldRunOnThread(command)) {
return runCommandOnThread(command, MESSAGE_OPTION_DEFAULT, false);
}
else {
return runCommandOffThread(command, MESSAGE_OPTION_DEFAULT);
}
}
// Runs the command.
// @param threadSafety The assumed thread safety of the command/program.
// @return true if command is successful; false otherwise.
public boolean runCommand(String command, Boolean threadSafety, int messageOption) throws AS400SecurityException, ErrorCompletingRequestException, IOException, InterruptedException
{
boolean runOnThread;
if (ON_THREAD.equals(threadSafety)) {
runOnThread = true;
}
else if (OFF_THREAD.equals(threadSafety)) {
runOnThread = false;
}
else // threadSafety == LOOKUP_THREADSAFETY
{
// Look up the command's indicated threadsafety on the system.
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "LOOKING-UP thread safety of command: " + command);
runOnThread = (getThreadsafeIndicator(command) == THREADSAFE_INDICATED_YES);
}
if (runOnThread) {
return runCommandOnThread(command, MESSAGE_OPTION_DEFAULT, false);
}
else {
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Delegating runCommand() to super class.");
return runCommandOffThread(command, messageOption);
}
}
// Runs the command.
// @return true if command is successful; false otherwise.
private boolean runCommandOnThread(String command, int messageOption, boolean currentlyOpeningOnThisThread) throws AS400SecurityException, ErrorCompletingRequestException, IOException, InterruptedException
{
if (Trace.traceOn_)
{
Trace.log(Trace.INFORMATION, "Native implementation running command: " + command);
Trace.log(Trace.DIAGNOSTIC, "Running command ON-THREAD: " + command);
}
if (!currentlyOpeningOnThisThread) openOnThread();
if (AS400.nativeVRM.vrm_ >= 0x00060100)
{
return runCommandOnThread(unicodeConverter_.stringToByteArray(command), messageOption, 1200);
}
return runCommandOnThread(converter_.stringToByteArray(command), messageOption, 0);
}
public boolean runCommand(byte[] commandAsBytes, String commandAsString) throws AS400SecurityException, ErrorCompletingRequestException, IOException, InterruptedException
{
// The caller didn't specify whether to call the command on- or off-thread.
// Base the decision on the setting the "threadSafe" system property.
if (shouldRunOnThread(commandAsString)) {
openOnThread();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Running command ON-THREAD: " + commandAsString);
return runCommandOnThread(commandAsBytes, MESSAGE_OPTION_DEFAULT, 0);
}
else {
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Running command OFF-THREAD: " + commandAsString);
return runCommandOffThread(commandAsBytes, MESSAGE_OPTION_DEFAULT, 0);
}
}
private boolean runCommandOnThread(byte[] commandBytes, int messageOption, int ccsid) throws AS400SecurityException, ErrorCompletingRequestException, IOException, InterruptedException
{
byte[] swapToPH = new byte[12];
byte[] swapFromPH = new byte[12];
boolean didSwap = system_.swapTo(swapToPH, swapFromPH);
if (OFF_THREAD.equals(priorCallWasOnThread_))
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Prior call was off-thread, but this call is on-thread, so different job.");
}
priorCallWasOnThread_ = ON_THREAD;
try
{
if (Trace.traceOn_) Trace.log(Trace.INFORMATION, "Invoking native method.");
if (AS400.nativeVRM.vrm_ < 0x00050300)
{
try
{
byte[] replyBytes = runCommandNative(commandBytes);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Native reply bytes:", replyBytes);
if (replyBytes == null) replyBytes = new byte[0];
// Get info from reply.
messageList_ = RemoteCommandImplNative.parseMessages(replyBytes, converter_);
return true;
}
catch (NativeException e) // Exception found by C code.
{
messageList_ = RemoteCommandImplNative.parseMessages(e.data, converter_);
return false;
}
}
else
{
try
{
byte[] replyBytes = AS400.nativeVRM.vrm_ < 0x00060100 ? runCommandNativeV5R3(commandBytes, messageOption) : NativeMethods.runCommand(commandBytes, ccsid, messageOption);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Native reply bytes:", replyBytes);
// Get info from reply.
messageList_ = RemoteCommandImplNative.parseMessagesV5R3(replyBytes, converter_);
return true;
}
catch (NativeException e) // Exception found by C code.
{
messageList_ = RemoteCommandImplNative.parseMessagesV5R3(e.data, converter_);
return false;
}
}
}
finally
{
if (didSwap) system_.swapBack(swapToPH, swapFromPH);
}
}
public boolean runProgram(String library, String name, ProgramParameter[] parameterList) throws AS400SecurityException, ErrorCompletingRequestException, IOException, InterruptedException, ObjectDoesNotExistException
{
// The caller didn't specify whether to call the command on- or off-thread.
// Base the decision on the setting the "threadSafe" system property.
String property = ProgramCall.getThreadSafetyProperty();
Boolean threadSafety;
if (property != null && property.equals("true")) {
threadSafety = ON_THREAD;
}
else threadSafety = OFF_THREAD;
return runProgram(library, name, parameterList, threadSafety);
}
public boolean runProgram(String library, String name, ProgramParameter[] parameterList, Boolean threadSafety) throws AS400SecurityException, ErrorCompletingRequestException, IOException, InterruptedException, ObjectDoesNotExistException
{
// Note: We don't have a way to look up the thread safety of programs.
if (ON_THREAD.equals(threadSafety)) {
return runProgramOnThread(library, name, parameterList, MESSAGE_OPTION_DEFAULT, false);
}
else {
return runProgramOffThread(library, name, parameterList, MESSAGE_OPTION_DEFAULT);
}
}
public boolean runProgram(String library, String name, ProgramParameter[] parameterList, Boolean threadSafety, int messageOption) throws AS400SecurityException, ErrorCompletingRequestException, IOException, InterruptedException, ObjectDoesNotExistException
{
// Note: We don't have a way to look up the thread safety of programs.
if (ON_THREAD.equals(threadSafety)) {
return runProgramOnThread(library, name, parameterList, messageOption, false);
}
else {
return runProgramOffThread(library, name, parameterList, messageOption);
}
}
// Run the program.
protected boolean runProgramOnThread(String library, String name, ProgramParameter[] parameterList, int messageOption, boolean currentlyOpeningOnThisThread) throws AS400SecurityException, ErrorCompletingRequestException, IOException, InterruptedException, ObjectDoesNotExistException
{
if (Trace.traceOn_)
{
Trace.log(Trace.INFORMATION, "Native implementation running program: " + library + "/" + name);
Trace.log(Trace.DIAGNOSTIC, "Running program ON-THREAD: " + library + "/" + name);
}
if (OFF_THREAD.equals(priorCallWasOnThread_))
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Prior call was off-thread, but this call is on-thread, so different job.");
}
priorCallWasOnThread_ = ON_THREAD;
// Run the program on-thread.
if (!currentlyOpeningOnThisThread) openOnThread();
if (AS400.nativeVRM.vrm_ < 0x00050300)
{
// Create a "call program" request, and write it as raw bytes to a byte array.
// Set up the buffer that contains the program to call. The buffer contains three items:
// 10 characters - the program to call.
// 10 characters - the library that contains the program.
// 4 bytes - the number of parameters.
byte[] programNameBuffer = {(byte)0x40, (byte)0x40, (byte)0x40, (byte)0x40, (byte)0x40, (byte)0x40, (byte)0x40, (byte)0x40, (byte)0x40, (byte)0x40, (byte)0x40, (byte)0x40, (byte)0x40, (byte)0x40, (byte)0x40, (byte)0x40, (byte)0x40, (byte)0x40, (byte)0x40, (byte)0x40, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00};
converter_.stringToByteArray(name, programNameBuffer);
converter_.stringToByteArray(library, programNameBuffer, 10);
BinaryConverter.intToByteArray(parameterList.length, programNameBuffer, 20);
// Set up the parameter structure. There is one structure for each parameters.
// The structure contains:
// 4 bytes - the length of the parameter.
// 2 bytes - the parameters usage (input/output/inout).
// 4 bytes - the offset into the parameter buffer.
byte[] programParameterStructure = new byte[parameterList.length * 10];
int totalParameterLength = 0;
for (int i = 0, offset = 0; i < parameterList.length; ++i)
{
int parameterMaxLength = parameterList[i].getMaxLength();
int parameterUsage = parameterList[i].getUsage();
if (parameterUsage == ProgramParameter.NULL)
{
// Server does not allow null parameters.
parameterUsage = ProgramParameter.INPUT;
}
BinaryConverter.intToByteArray(parameterMaxLength, programParameterStructure, i * 10);
BinaryConverter.unsignedShortToByteArray(parameterUsage, programParameterStructure, i * 10 + 4);
BinaryConverter.intToByteArray(offset, programParameterStructure, i * 10 + 6);
offset += parameterMaxLength;
totalParameterLength += parameterMaxLength;
}
// Set up the Parameter area.
byte[] programParameters = new byte[totalParameterLength];
for (int i = 0, offset = 0; i < parameterList.length; ++i)
{
byte[] inputData = parameterList[i].getInputData();
int parameterMaxLength = parameterList[i].getMaxLength();
if (inputData != null)
{
System.arraycopy(inputData, 0, programParameters, offset, inputData.length);
}
offset += parameterMaxLength;
}
if (Trace.traceOn_)
{
Trace.log(Trace.DIAGNOSTIC, "Program name bytes:", programNameBuffer);
Trace.log(Trace.DIAGNOSTIC, "Program parameter bytes:", programParameterStructure);
Trace.log(Trace.DIAGNOSTIC, "Program parameters:", programParameters);
}
byte[] swapToPH = new byte[12];
byte[] swapFromPH = new byte[12];
boolean didSwap = system_.swapTo(swapToPH, swapFromPH);
try
{
// Call native method.
if (Trace.traceOn_) Trace.log(Trace.INFORMATION, "Invoking native method.");
byte[] replyBytes = runProgramNative(programNameBuffer, programParameterStructure, programParameters);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Native reply bytes:", replyBytes);
// Reset the message list.
messageList_ = new AS400Message[0];
// For each output/inout parm, in order, set data returned.
for (int index = 0, i = 0; i < parameterList.length; ++i)
{
int parameterMaxLength = parameterList[i].getMaxLength();
int outputDataLength = parameterList[i].getOutputDataLength();
if (outputDataLength > 0)
{
byte[] outputData = new byte[outputDataLength];
System.arraycopy(replyBytes, index, outputData, 0, outputDataLength);
parameterList[i].setOutputData(outputData);
}
index += parameterMaxLength;
}
return true;
}
catch (NativeException e) // Exception found by C code.
{
messageList_ = RemoteCommandImplNative.parseMessages(e.data, converter_);
if (messageList_.length == 0) return false;
// Parse information from byte array.
String id = messageList_[messageList_.length - 1].getID();
if (id.equals("MCH3401"))
{
byte[] substitutionBytes = messageList_[messageList_.length - 1].getSubstitutionData();
if (substitutionBytes[0] == 0x02 && substitutionBytes[1] == 0x01 && name.equals(converter_.byteArrayToString(substitutionBytes, 2, 30).trim()))
{
throw new ObjectDoesNotExistException(QSYSObjectPathName.toPath(library, name, "PGM"), ObjectDoesNotExistException.OBJECT_DOES_NOT_EXIST);
}
if (substitutionBytes[0] == 0x04 && substitutionBytes[1] == 0x01 && library.equals(converter_.byteArrayToString(substitutionBytes, 2, 30).trim()))
{
throw new ObjectDoesNotExistException(QSYSObjectPathName.toPath(library, name, "PGM"), ObjectDoesNotExistException.LIBRARY_DOES_NOT_EXIST);
}
}
return false;
}
finally
{
if (didSwap) system_.swapBack(swapToPH, swapFromPH);
}
}
else
{
byte[] tempBytes = converter_.stringToByteArray(name);
byte[] nameBytes = new byte[tempBytes.length + 1];
System.arraycopy(tempBytes, 0, nameBytes, 0, tempBytes.length);
tempBytes = converter_.stringToByteArray(library);
byte[] libraryBytes = new byte[tempBytes.length + 1];
System.arraycopy(tempBytes, 0, libraryBytes, 0, tempBytes.length);
byte[] offsetArray = new byte[parameterList.length * 4];
int totalParameterLength = 0;
for (int i = 0; i < parameterList.length; ++i)
{
if (parameterList[i].getUsage() == ProgramParameter.NULL)
{
BinaryConverter.intToByteArray(-1, offsetArray, i * 4);
}
else
{
BinaryConverter.intToByteArray(totalParameterLength, offsetArray, i * 4);
}
totalParameterLength += parameterList[i].getMaxLength();
}
// Set up the Parameter area.
byte[] programParameters = new byte[totalParameterLength];
for (int i = 0, offset = 0; i < parameterList.length; ++i)
{
byte[] inputData = parameterList[i].getInputData();
if (inputData != null)
{
System.arraycopy(inputData, 0, programParameters, offset, inputData.length);
}
offset += parameterList[i].getMaxLength();
}
if (Trace.traceOn_)
{
Trace.log(Trace.DIAGNOSTIC, "Program name bytes:", nameBytes);
Trace.log(Trace.DIAGNOSTIC, "Program library bytes:", libraryBytes);
Trace.log(Trace.DIAGNOSTIC, "Number of parameters:", parameterList.length);
Trace.log(Trace.DIAGNOSTIC, "Offset array:", offsetArray);
Trace.log(Trace.DIAGNOSTIC, "Program parameters:", programParameters);
}
byte[] swapToPH = new byte[12];
byte[] swapFromPH = new byte[12];
boolean didSwap = system_.swapTo(swapToPH, swapFromPH);
try
{
// Call native method.
if (Trace.traceOn_) Trace.log(Trace.INFORMATION, "Invoking native method.");
byte[] replyBytes = AS400.nativeVRM.vrm_ < 0x00060100 ? runProgramNativeV5R3(nameBytes, libraryBytes, parameterList.length, offsetArray, programParameters, messageOption) : NativeMethods.runProgram(nameBytes, libraryBytes, parameterList.length, offsetArray, programParameters, messageOption);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Native reply bytes:", replyBytes);
// Reset the message list.
messageList_ = new AS400Message[0];
// For each output/inout parm, in order, set data returned.
for (int index = 0, i = 0; i < parameterList.length; ++i)
{
int outputDataLength = parameterList[i].getOutputDataLength();
if (outputDataLength > 0)
{
byte[] outputData = new byte[outputDataLength];
System.arraycopy(replyBytes, index, outputData, 0, outputDataLength);
parameterList[i].setOutputData(outputData);
}
index += parameterList[i].getMaxLength();
}
return true;
}
catch (NativeException e) // Exception found by C code.
{
messageList_ = RemoteCommandImplNative.parseMessagesV5R3(e.data, converter_);
if (messageList_.length == 0) return false;
// Parse information from byte array.
String id = messageList_[messageList_.length - 1].getID();
if (id.equals("MCH3401"))
{
byte[] substitutionBytes = messageList_[messageList_.length - 1].getSubstitutionData();
if (substitutionBytes[0] == 0x02 && substitutionBytes[1] == 0x01 && name.equals(converter_.byteArrayToString(substitutionBytes, 2, 30).trim()))
{
throw new ObjectDoesNotExistException(QSYSObjectPathName.toPath(library, name, "PGM"), ObjectDoesNotExistException.OBJECT_DOES_NOT_EXIST);
}
if (substitutionBytes[0] == 0x04 && substitutionBytes[1] == 0x01 && library.equals(converter_.byteArrayToString(substitutionBytes, 2, 30).trim()))
{
throw new ObjectDoesNotExistException(QSYSObjectPathName.toPath(library, name, "PGM"), ObjectDoesNotExistException.LIBRARY_DOES_NOT_EXIST);
}
}
return false;
}
finally
{
if (didSwap) system_.swapBack(swapToPH, swapFromPH);
}
}
}
static AS400Message[] parseMessages(byte[] data, ConverterImplRemote converter)
{
int messageNumber = data.length / 10240;
AS400Message[] messageList = new AS400Message[messageNumber];
for (int offset = 0, i = 0; i < messageNumber; ++i)
{
messageList[i] = new AS400Message();
messageList[i].setID(converter.byteArrayToString(data, offset + 12, 7));
messageList[i].setType((data[offset + 19] & 0x0F) * 10 + (data[offset + 20] & 0x0F));
messageList[i].setSeverity(BinaryConverter.byteArrayToInt(data, offset + 8));
messageList[i].setFileName(converter.byteArrayToString(data, offset + 25, 10).trim());
messageList[i].setLibraryName(converter.byteArrayToString(data, offset + 45, 10).trim());
int substitutionDataLength = BinaryConverter.byteArrayToInt(data, offset + 80);
int textLength = BinaryConverter.byteArrayToInt(data, offset + 88);
byte[] substitutionData = new byte[substitutionDataLength];
System.arraycopy(data, offset + 112, substitutionData, 0, substitutionDataLength);
messageList[i].setSubstitutionData(substitutionData);
messageList[i].setText(converter.byteArrayToString(data, offset + 112 + substitutionDataLength, textLength));
offset += 10240;
}
return messageList;
}
static AS400Message[] parseMessagesV5R3(byte[] data, ConverterImplRemote converter)
{
int messageNumber = BinaryConverter.byteArrayToInt(data, 0);
AS400Message[] messageList = new AS400Message[messageNumber];
for (int offset = 4, i = 0; i < messageNumber; ++i)
{
messageList[i] = new AS400Message();
messageList[i].setID(converter.byteArrayToString(data, offset + 12, 7));
messageList[i].setType((data[offset + 19] & 0x0F) * 10 + (data[offset + 20] & 0x0F));
messageList[i].setSeverity(BinaryConverter.byteArrayToInt(data, offset + 8));
messageList[i].setFileName(converter.byteArrayToString(data, offset + 25, 10).trim());
messageList[i].setLibraryName(converter.byteArrayToString(data, offset + 45, 10).trim());
int substitutionDataLength = BinaryConverter.byteArrayToInt(data, offset + 80);
int textLength = BinaryConverter.byteArrayToInt(data, offset + 88);
int helpLength = BinaryConverter.byteArrayToInt(data, offset + 96);
byte[] substitutionData = new byte[substitutionDataLength];
System.arraycopy(data, offset + 112, substitutionData, 0, substitutionDataLength);
messageList[i].setSubstitutionData(substitutionData);
messageList[i].setText(converter.byteArrayToString(data, offset + 112 + substitutionDataLength, textLength));
messageList[i].setHelp(converter.byteArrayToString(data, offset + 112 + substitutionDataLength + textLength, helpLength));
offset += BinaryConverter.byteArrayToInt(data, offset);
offset += BinaryConverter.byteArrayToInt(data, offset);
}
return messageList;
}
// Determines whether or not the command should be called on-thread.
private final boolean shouldRunOnThread(String command) throws AS400SecurityException, ErrorCompletingRequestException, IOException, InterruptedException
{
boolean runOnThread;
// Check the threadSafe property, and apply it if set.
String property = CommandCall.getThreadSafetyProperty();
if ((property == null) || (property.equals("false"))) {
runOnThread = false;
}
else if (property.equals("true")) {
runOnThread = true;
}
else if (property.equals("lookup")) {
// Look it up on the system.
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "LOOKING-UP thread safety of command: " + command);
runOnThread = (getThreadsafeIndicator(command) == THREADSAFE_INDICATED_YES);
}
else {
runOnThread = false;
// Assume the utility method has logged a warning about unrecognized property value.
}
return runOnThread;
}
private native byte[] runCommandNative(byte[] command) throws NativeException;
private static native byte[] runCommandNativeV5R3(byte[] command, int messageOption) throws NativeException;
private native byte[] runProgramNative(byte[] programNameBuffer, byte[] programParameterStructure, byte[] programParameters) throws NativeException;
private static native byte[] runProgramNativeV5R3(byte[] name, byte[] library, int numberParameters, byte[] offsetArray, byte[] programParameters, int messageOption) throws NativeException;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy