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 Show documentation
Show all versions of jt400 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