src.com.ibm.as400.access.UserSpaceImplRemote Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jt400-jdk8 Show documentation
Show all versions of jt400-jdk8 Show documentation
The Open Source version of the IBM Toolbox for Java
The newest version!
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: UserSpaceImplRemote.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-2003 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.access;
import java.beans.PropertyVetoException;
import java.io.FileNotFoundException;
import java.io.IOException;
// The UserSpaceImplRemote class is the remote implementation of the user space class.
class UserSpaceImplRemote implements UserSpaceImpl
{
// The server where the user space is located.
protected AS400ImplRemote system_ = null;
// The full path name of the user space.
protected String path_ = null;
// The library that contains the user space.
protected String library_ = null;
// The name of the user space.
protected String name_ = null;
// Use ProgramCall instead of IFS.
protected boolean mustUseProgramCall_ = false;
// Use sockets instead of native methods when running natively.
protected boolean mustUseSockets_ = false;
// The string to byte data converter.
protected ConverterImplRemote converter_;
// Qualified user space name parameter, set on first touch.
private ProgramParameter nameParameter_ = null;
// Error code parameter for API's, set on first touch.
private ProgramParameter errorCodeParameter_ = null;
// Impl object for remote command server delete, getAttributes, setAttributes.
protected RemoteCommandImpl remoteCommand_;
// Whether to call remote commands on-thread.
private Boolean runOnThread_ = RemoteCommandImpl.OFF_THREAD;
// The integrated file system object used for read and write.
private IFSRandomAccessFileImplRemote file_;
// Throw or return an exception based on the message list from a remote program call.
private AS400Exception buildException() throws AS400SecurityException, ObjectDoesNotExistException
{
// Get the message list.
AS400Message[] messageList = remoteCommand_.getMessageList();
// Get the message id of the first message.
String id = messageList[0].getID();
// Throw appropriate exceptions for not existing or not authorized.
if (id.equals("CPF9801") || id.equals("CPF2105"))
{
Trace.log(Trace.ERROR, "Object does not exist: " + path_);
throw new ObjectDoesNotExistException(path_, ObjectDoesNotExistException.OBJECT_DOES_NOT_EXIST);
}
if (id.equals("CPF9802") || id.equals("CPF2189"))
{
Trace.log(Trace.ERROR, "User is not authorized to object: " + path_);
throw new AS400SecurityException(path_, AS400SecurityException.OBJECT_AUTHORITY_INSUFFICIENT);
}
if (id.equals("CPF9810") || id.equals("CPF2209") || id.equals("CPF2110"))
{
Trace.log(Trace.ERROR, "Library does not exist: " + path_);
throw new ObjectDoesNotExistException(path_, ObjectDoesNotExistException.LIBRARY_DOES_NOT_EXIST);
}
if (id.equals("CPF9820") || id.equals("CPF2182"))
{
Trace.log(Trace.ERROR, "User is not authorized to library: " + path_);
throw new AS400SecurityException(path_, AS400SecurityException.LIBRARY_AUTHORITY_INSUFFICIENT);
}
if (id.equals("CPF2283"))
{
String authorizationListName = "/QSYS.LIB/" + converter_.byteArrayToString(messageList[0].getSubstitutionData()).trim() + ".AUTL";
Trace.log(Trace.ERROR, "Object does not exist: " + authorizationListName);
throw new ObjectDoesNotExistException(authorizationListName, ObjectDoesNotExistException.OBJECT_DOES_NOT_EXIST);
}
// Else return exception for messages.
return new AS400Exception(messageList);
}
// Closes our file stream to the user space (if a stream has been created),
// and releases any system resources associated with the stream.
// This will not close the connection to the Host Server job held by the associated AS400 object.
public void close() throws IOException
{
if (file_ != null)
{
// Close the random access file stream.
file_.close();
// Clear the file connection info.
file_ = null;
}
}
// Creates a user space.
public void create(byte[] domainBytes, int length, boolean replace, String extendedAttribute, byte initialValue, String textDescription, String authority) throws AS400SecurityException, ErrorCompletingRequestException, InterruptedException, IOException, ObjectDoesNotExistException
{
// Close the file stream to the user space (if one already exists).
close();
// Setup qualified user space name parameter.
setupNameParameter();
// Setup error code parameter.
setupErrorCodeParameter();
// Setup program call parameters.
ProgramParameter[] parameters = new ProgramParameter[]
{
// Qualified user space name, input, char(20).
nameParameter_,
// Extended attributes, input, char(10).
new ProgramParameter(padByteArray(converter_.stringToByteArray(extendedAttribute), 10)),
// Initial size, input, binary(4).
new ProgramParameter(BinaryConverter.intToByteArray(length)),
// Initial value, input, char(1).
new ProgramParameter(new byte[] { initialValue }),
// Public authority, input, char(10).
new ProgramParameter(padByteArray(converter_.stringToByteArray(authority), 10)),
// Text description, input, char(50).
new ProgramParameter(padByteArray(converter_.stringToByteArray(textDescription), 50)),
// Replace, input, char(10), EBCDIC "*YES" or "*NO".
new ProgramParameter((replace) ? new byte[] { 0x5C, (byte)0xE8, (byte)0xC5, (byte)0xE2, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 } : new byte[] { 0x5C, (byte)0xD5, (byte)0xD6, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 } ),
// Error code, input/output, char(*).
errorCodeParameter_,
// Domain, input, char(10).
new ProgramParameter(domainBytes),
// Transfer size request, input, binary(4).
new ProgramParameter(new byte[] { 0x00, 0x00, 0x00, 0x00 } ),
// Optimum space alignment, input, char(1).
new ProgramParameter(new byte[] { length > 16773120 ? (byte)0xF0 : (byte)0xF1 } )
};
// Setup for remote program call.
if (remoteCommand_ == null) {
setupRemoteCommand();
}
// Run create user space (QUSCRTUS) API. This is a threadsafe API.
if (!remoteCommand_.runProgram("QSYS", "QUSCRTUS", parameters, runOnThread_))
{
// Throw the returned messages.
throw buildException();
}
}
// Return a byte array padded to the correct length.
private static byte[] padByteArray(byte[] bytes, int length)
{
byte[] result = new byte[length];
System.arraycopy(bytes, 0, result, 0, bytes.length);
for (int i = bytes.length; i < length; ++i) result[i] = 0x40;
return result;
}
// Deletes a user space.
public void delete() throws AS400SecurityException, ErrorCompletingRequestException, InterruptedException, IOException, ObjectDoesNotExistException
{
// Close the file stream to the user space (if one exists), to avoid locking problems.
close();
// Setup qualified user space name parameter.
setupNameParameter();
// Setup error code parameter.
setupErrorCodeParameter();
// Setup program call parameters.
ProgramParameter[] parameters = new ProgramParameter[]
{
// Qualified user space name, input, char(20).
nameParameter_,
// Error code, input/output, char(*).
errorCodeParameter_
};
// Setup for remote program call.
if (remoteCommand_ == null) {
setupRemoteCommand();
}
// Run delete user space (QUSDLTUS) API. This is a threadsafe API.
if (!remoteCommand_.runProgram("QSYS", "QUSDLTUS", parameters, runOnThread_))
{
// Throw the returned messages.
throw buildException();
}
}
// Returns the initial value used for filling in the user space during creation and extension.
public byte getInitialValue() throws AS400SecurityException, ErrorCompletingRequestException, InterruptedException, IOException, ObjectDoesNotExistException
{
return retrieveAttributes()[13];
}
// Returns the size in bytes of the user space.
public int getLength() throws AS400SecurityException, ErrorCompletingRequestException, InterruptedException, IOException, ObjectDoesNotExistException
{
return BinaryConverter.byteArrayToInt(retrieveAttributes(), 8);
}
// Indicates if the user space is auto extendible.
public boolean isAutoExtendible() throws AS400SecurityException, ErrorCompletingRequestException, InterruptedException, IOException, ObjectDoesNotExistException
{
return retrieveAttributes()[12] == (byte)0xF1;
}
// Retrieve the user space attributes.
protected byte[] retrieveAttributes() throws AS400SecurityException, ErrorCompletingRequestException, InterruptedException, IOException, ObjectDoesNotExistException
{
// Close the file stream to the user space (if one exists), to avoid locking problems.
close();
// Setup qualified user space name parameter.
setupNameParameter();
// Setup error code parameter.
setupErrorCodeParameter();
// Setup program call parameters.
ProgramParameter[] parameters = new ProgramParameter[]
{
// Receiver variable, output, char(*), ask for 24 bytes.
new ProgramParameter(24),
// Length of receiver variable, input, binary(4), 24 bytes.
new ProgramParameter(new byte[] { 0x00, 0x00, 0x00, 0x18 } ),
// Format name, input, char(8), EBCDIC "SPCA0100".
new ProgramParameter(new byte[] { (byte)0xE2, (byte)0xD7, (byte)0xC3, (byte)0xC1, (byte)0xF0, (byte)0xF1, (byte)0xF0, (byte)0xF0 } ),
// Qualified user space name, input, char(20).
nameParameter_,
// Error code, input/output, char(*).
errorCodeParameter_
};
// Setup for remote program call.
if (remoteCommand_ == null) {
setupRemoteCommand();
}
// Run retrieve user space attributes (QUSRUSAT) API. This is a threadsafe API.
if (!remoteCommand_.runProgram("QSYS", "QUSRUSAT", parameters, runOnThread_))
{
// Throw the returned messages.
throw buildException();
}
// Return the data returned from the program.
return parameters[0].getOutputData();
}
// Read from user space.
public int read(byte[] dataBuffer, int userSpaceOffset, int dataOffset, int length) throws AS400SecurityException, ErrorCompletingRequestException, InterruptedException, IOException, ObjectDoesNotExistException
{
// Use remote program call implementation or file implementation.
if (mustUseProgramCall_)
{
// Setup qualified user space name parameter.
setupNameParameter();
// Setup program call parameters.
ProgramParameter[] parameters = new ProgramParameter[]
{
// Qualified user space name, input, char(20).
nameParameter_,
// Starting position, input, binary(4), add 1 for 1 based offset.
new ProgramParameter(BinaryConverter.intToByteArray(userSpaceOffset + 1)),
// Length of data, input, binary(4).
new ProgramParameter(BinaryConverter.intToByteArray(length)),
// Receiver variable, output, char(*).
new ProgramParameter(length)
// Omit error code optional parameter.
};
// Setup for remote program call.
if (remoteCommand_ == null) {
setupRemoteCommand();
}
// Run retrieve user space (QUSRTVUS) API. This is a threadsafe API.
if (!remoteCommand_.runProgram("QSYS", "QUSRTVUS", parameters, runOnThread_))
{
String id = remoteCommand_.getMessageList()[0].getID();
if (!id.equals("CPF3C14") && !id.equals("CPD3C14"))
{
// Throw the returned messages.
throw buildException();
}
int userSpaceLength = getLength();
if (userSpaceLength < userSpaceOffset) return -1;
length = userSpaceLength - userSpaceOffset;
try
{
parameters[2].setInputData(BinaryConverter.intToByteArray(length));
parameters[3].setOutputDataLength(length);
}
catch (PropertyVetoException e)
{
Trace.log(Trace.ERROR, "Unexpected PropertyVetoException:", e);
throw new InternalErrorException(InternalErrorException.UNEXPECTED_EXCEPTION);
}
if (!remoteCommand_.runProgram("QSYS", "QUSRTVUS", parameters, runOnThread_))
{
// Throw the returned messages.
throw buildException();
}
}
// Copy output data into user's array.
System.arraycopy(parameters[3].getOutputData(), 0, dataBuffer, dataOffset, length);
return length;
}
else
{
// Setup for file.
setupFile();
// Seek to correct offset.
file_.seek(userSpaceOffset);
// Read from the user space, return number of bytes read.
return file_.read(dataBuffer, dataOffset, length, false);
}
}
// Sets the auto extend attribute.
public void setAutoExtendible(boolean autoExtendibility) throws AS400SecurityException, ErrorCompletingRequestException, InterruptedException, IOException, ObjectDoesNotExistException
{
// Number of attributes is 1, key is 3, length of attribute is 1 byte, value is EBCDIC "1" or "0".
changeAttributes(new byte[] { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, autoExtendibility ? (byte)0xF1 : (byte)0xF0 });
}
// Sets the initial value to be used during user space creation or extension.
public void setInitialValue(byte initialValue) throws AS400SecurityException, ErrorCompletingRequestException, InterruptedException, IOException, ObjectDoesNotExistException
{
// Number of attributes is 1, key is 2, length of attribute is 1 byte, value is as specified.
changeAttributes(new byte[] { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, initialValue });
}
// Sets the size of the user space. Valid values are 1 through 1,6776,704.
public void setLength(int length) throws AS400SecurityException, ErrorCompletingRequestException, InterruptedException, IOException, ObjectDoesNotExistException
{
// Number of attributes is 1, key is 1, length of attribute is 4 bytes, use 4 bytes of 0 to hold space for value.
byte[] attributeBytes = new byte[] { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00 };
// Set the length into the 12th position of the byte array.
BinaryConverter.intToByteArray(length, attributeBytes, 12);
changeAttributes(attributeBytes);
}
// Change the user space attributes.
protected void changeAttributes(byte[] attributeBytes) throws AS400SecurityException, ErrorCompletingRequestException, InterruptedException, IOException, ObjectDoesNotExistException
{
// Close the file stream to the user space (if one exists), to avoid locking problems.
close();
// Setup qualified user space name parameter.
setupNameParameter();
// Setup error code parameter.
setupErrorCodeParameter();
// Setup program call parameters.
ProgramParameter[] parameters = new ProgramParameter[]
{
// Returned library name, output, char(10).
new ProgramParameter(10),
// Qualified user space name, input, char(20).
nameParameter_,
// Attribtes to change, input, char(*).
new ProgramParameter(attributeBytes),
// ErrorCode, input/output, char(*).
errorCodeParameter_
};
// Setup for remote program call.
if (remoteCommand_ == null) {
setupRemoteCommand();
}
// Run change user space attributes (QUSCUSAT) API. This is a threadsafe API.
if (!remoteCommand_.runProgram("QSYS", "QUSCUSAT", parameters, runOnThread_))
{
// Throw the returned messages.
throw buildException();
}
}
// Set needed implementation properties.
public void setProperties(AS400Impl system, String path, String name, String library, boolean mustUseProgramCall, boolean mustUseSockets)
{
system_ = (AS400ImplRemote)system;
path_ = path;
library_ = library;
name_ = name;
mustUseProgramCall_ = mustUseProgramCall;
mustUseSockets_ = mustUseSockets;
}
// Setup error code program parameter object on first touch. Synchronized to protect instance variables. This method can safely be called multiple times because it checks for a previous call before changing the instance variables.
private void setupErrorCodeParameter()
{
// If not already setup.
if (errorCodeParameter_ == null)
{
// Set error code parameter to eight bytes of zero's. This causes the messages to be issued to the API caller.
errorCodeParameter_ = new ProgramParameter(new byte[8]);
}
}
// Setup file object on first touch. Synchronized to protect instance variables. This method can safely be called multiple times because it checks for a previous call before changing the instance variables.
private synchronized void setupFile() throws AS400SecurityException, IOException, ObjectDoesNotExistException
{
// If not already setup.
if (file_ == null)
{
try
{
// Create the file descriptor implementation object.
IFSFileDescriptorImplRemote fd_ = new IFSFileDescriptorImplRemote();
// Set the necessary properties into it.
fd_.initialize(0, this, path_, IFSRandomAccessFile.SHARE_ALL, system_);
// Create the file implementation object.
file_ = new IFSRandomAccessFileImplRemote();
// Set the necessary properties into it.
file_.setFD(fd_);
file_.setMode("rw");
file_.setExistenceOption(IFSRandomAccessFile.OPEN_OR_FAIL);
// Open the file.
file_.open();
}
catch (FileNotFoundException e)
{
Trace.log(Trace.ERROR, "Object does not exist: " + path_, e);
throw new ObjectDoesNotExistException(path_, ObjectDoesNotExistException.OBJECT_DOES_NOT_EXIST);
}
catch (ExtendedIOException e)
{
if (e.getReturnCode() == ExtendedIOException.ACCESS_DENIED)
{
Trace.log(Trace.ERROR, "User is not authorized to object: " + path_, e);
throw new AS400SecurityException(path_, AS400SecurityException.OBJECT_AUTHORITY_INSUFFICIENT);
}
if (e.getReturnCode() == ExtendedIOException.REQUEST_NOT_SUPPORTED && library_.equals("QTEMP"))
{
// File server cannot access QTEMP library.
Trace.log(Trace.WARNING, "File server cannot access QTEMP, use mustUseProgramCall option.");
}
Trace.log(Trace.ERROR, "Error opening file: " + path_, e);
throw e;
}
}
}
// Setup qualified user space name program parameter object on first touch. Synchronized to protect instance variables. This method can safely be called multiple times because it checks for a previous call before changing the instance variables.
private synchronized void setupNameParameter() throws IOException
{
// If not already setup.
if (nameParameter_ == null)
{
// Get a converter for the system objects CCSID.
converter_ = ConverterImplRemote.getConverter((system_).getCcsid(), system_);
// The name and library of the user space used in program call. Start with 20 EBCDIC spaces (" ").
byte[] qualifiedUserSpaceName = new byte[] { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 };
// Put the converted object name at the beginning of the array.
converter_.stringToByteArray(name_, qualifiedUserSpaceName, 0);
// Put the converted library name at position ten.
converter_.stringToByteArray(library_, qualifiedUserSpaceName, 10);
// Create the program parameter object.
nameParameter_ = new ProgramParameter(qualifiedUserSpaceName);
}
}
// Setup remote command object on first touch. Synchronized to protect instance variables. This method can safely be called multiple times because it checks for a previous call before changing the instance variables.
protected synchronized void setupRemoteCommand() throws IOException
{
// If not already setup.
if (remoteCommand_ == null)
{
boolean runningNatively = false;
if (system_.canUseNativeOptimizations())
{
try
{
remoteCommand_ = (RemoteCommandImpl)Class.forName("com.ibm.as400.access.RemoteCommandImplNative").newInstance();
// Avoid direct reference - it can cause NoClassDefFoundError at class loading time on Sun JVM's.
runningNatively = true;
}
catch (Throwable e) {
// A ClassNotFoundException would be unexpected, since canUseNativeOptions() returned true.
Trace.log(Trace.WARNING, "Unable to instantiate class RemoteCommandImplNative.", e);
}
}
if (remoteCommand_ == null)
{
remoteCommand_ = new RemoteCommandImplRemote();
}
remoteCommand_.setSystem(system_);
// Note: All the API's that are called from this class, are threadsafe API's.
// However, we need to stay consistent with the Toolbox's default threadsafety behavior.
// So we'll indicate that the remote commands can safely be run on-thread (but only if the threadSafe property isn't set to 'false'). This will enable applications to use UserSpace when running on IBM i and using a profile that is disabled or has password *NONE.
if (runningNatively && !mustUseSockets_)
{
// Abide by the setting of the thread-safety property (if it's set).
String propVal = ProgramCall.getThreadSafetyProperty();
if (propVal == null || !propVal.equals("false"))
{
runOnThread_ = RemoteCommandImpl.ON_THREAD;
}
}
}
}
// Remote implementation of write.
public void write(byte[] dataBuffer, int userSpaceOffset, int dataOffset, int length, int force) throws AS400SecurityException, ErrorCompletingRequestException, InterruptedException, IOException, ObjectDoesNotExistException
{
// Use remote program call implementation or file implementation.
if (mustUseProgramCall_)
{
// Setup qualified user space name parameter.
setupNameParameter();
// Allocate parameter array bytes.
byte[] inputData = new byte[length];
// Copy data into parameter array.
System.arraycopy(dataBuffer, dataOffset, inputData, 0, length);
// Setup program call parameters.
ProgramParameter[] parameters = new ProgramParameter[]
{
// Qualified user space name, input, char(20).
nameParameter_,
// Starting position, input, binary(4), add 1 for 1 based offset.
new ProgramParameter(BinaryConverter.intToByteArray(userSpaceOffset + 1)),
// Length of data, input, binary(4).
new ProgramParameter(BinaryConverter.intToByteArray(length)),
// Input data, input, char(*).
new ProgramParameter(inputData),
// Force changes to auxiliary storage, input, char(1).
new ProgramParameter(new byte[] { (byte)(0xF0 | force) } )
// Omit error code optional parameter.
};
// Setup for remote program call.
if (remoteCommand_ == null) {
setupRemoteCommand();
}
// Run change user space (QUSCHGUS) API. This is a threadsafe API.
if (!remoteCommand_.runProgram("QSYS", "QUSCHGUS", parameters, runOnThread_))
{
// Throw the returned messages.
throw buildException();
}
}
else
{
// Setup for file.
setupFile();
// Seek to correct offset.
file_.seek(userSpaceOffset);
// Set force option.
switch (force)
{
case UserSpace.FORCE_SYNCHRONOUS:
file_.setForceToStorage(true);
break;
case UserSpace.FORCE_ASYNCHRONOUS:
file_.setForceToStorage(false);
break;
}
// Write data.
file_.writeBytes(dataBuffer, dataOffset, length);
}
}
}