com.ibm.as400.access.AS400 Maven / Gradle / Ivy
Show all versions of jt400 Show documentation
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: AS400.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-2024 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.access;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.URL;
import java.util.Arrays;
import java.util.GregorianCalendar;
import java.util.Hashtable;
import java.util.Locale;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.Vector;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSManager;
import com.ibm.as400.security.auth.ProfileTokenCredential;
import com.ibm.as400.security.auth.ProfileTokenEnhancedInfo;
import com.ibm.as400.security.auth.ProfileTokenProvider;
/**
* Represents the authentication information and a set of connections to the IBM i host servers.
*
* If running on IBM i or an older version of that operating system, the system name, user ID, and password do not need
* to be supplied. These values default to the local system. For the system name, the keyword localhost
can
* be used to specify the local system. For the user ID and password, *CURRENT can be used.
*
* If running on another operating system, the system name, user ID, and password need to be supplied. If not supplied,
* the first 'open' request associated with this object will trigger a prompt to the workstation user. Subsequent opens
* associated with the same object will not prompt the workstation user. Keywords localhost
and *CURRENT
* will not work when running on another operating system.
*
* For example:
*
*
AS400 system = new AS400();
system.connectService(AS400.DATAQUEUE); // This causes a password prompt.
...
system.connectService(AS400.FILE); // This does not cause a prompt.
*
**/
public class AS400 implements Serializable, AutoCloseable
{
private static final String CLASSNAME = "com.ibm.as400.access.AS400";
static
{
if (Trace.traceOn_) Trace.logLoadPath(CLASSNAME);
}
static final long serialVersionUID = 4L;
private static final boolean PASSWORD_TRACE = false;
/** Constant indicating the File service. **/
public static final int FILE = 0;
/** Constant indicating the Print service. **/
public static final int PRINT = 1;
/** Constant indicating the Command service. **/
public static final int COMMAND = 2;
/** Constant indicating the Dataqueue service. **/
public static final int DATAQUEUE = 3;
/** Constant indicating the Database service. **/
public static final int DATABASE = 4;
/** Constant indicating the Record Access service. **/
public static final int RECORDACCESS = 5;
/** Constant indicating the Central service. **/
public static final int CENTRAL = 6;
/** Constant indicating the Sign-on service. **/
public static final int SIGNON = 7;
/** Constant indicating the Host connection service. */
public static final int HOSTCNN = 8;
// Constants 8-15 reserved for SSL versions of the above services.
/** Special value indicating the service port should be retrieved from the port mapper server. **/
public static final int USE_PORT_MAPPER = -1;
/** Constant indicating the authentication scheme is password. **/
public static final int AUTHENTICATION_SCHEME_PASSWORD = 0;
/** Constant indicating the authentication scheme is GSS token. **/
public static final int AUTHENTICATION_SCHEME_GSS_TOKEN = 1;
/** Constant indicating the authentication scheme is profile token. **/
public static final int AUTHENTICATION_SCHEME_PROFILE_TOKEN = 2;
/** Constant indicating the authentication scheme is identity token. **/
public static final int AUTHENTICATION_SCHEME_IDENTITY_TOKEN = 3;
/** Constant representing the DDM_EUSERIDPWD scheme - only applicable to Record Access service. */
public static final int AUTHENTICATION_SCHEME_DDM_EUSERIDPWD = 4;
/**
Constant indicating that the JGSS framework must be used when no password or authentication token is set.
An object set to this option will not attempt to present a sign-on dialog or use the current user profile information.
A failure to retrieve the GSS token will result in an exception returned to the user.
**/
public static final int GSS_OPTION_MANDATORY = 0;
/**
Constant indicating that the JGSS framework will be attempted when no password or authentication token is set.
An object set to this option will attempt to retrieve a GSS token, if that attempt fails, the object will present
a sign-on dialog or use the current user profile information. This option is the default.
**/
public static final int GSS_OPTION_FALLBACK = 1;
/**
Constant indicating that the JGSS framework will not be used when no password or authentication token is set.
An object set to this option will only present a sign-on dialog or use the current user profile information.
**/
public static final int GSS_OPTION_NONE = 2;
/**
Constant indicating that encryption should only be done on the connection between the client and the proxy server.
**/
public static final int CLIENT_TO_PROXY_SERVER = 1;
/**
Constant indicating that encryption should only be done on the connection between the proxy server and the system.
**/
public static final int PROXY_SERVER_TO_SERVER = 2;
/** @deprecated Use CLIENT_TO_SERVER instead. **/
public static final int CLINT_TO_SERVER = 3;
/**
Constant indicating that encryption should be done in both the connection between the client and the proxy server
and the connection between the proxy server and the system.
**/
public static final int CLIENT_TO_SERVER = 3;
/** Indicate whether the cipher suites changed by the caller. We add this for iNav. */
public static boolean changeCipherSuites = false;
public static String[] newCipherSuites;
// Determine if we are running on IBM i.
static boolean onAS400 = false;
// VRM from system property, if we are native.
static ServerVersion nativeVRM = null;
// The static default sign-on handler.
static Class defaultSignonHandlerClass_ = ToolboxSignonHandler.class;
static SignonHandler defaultSignonHandler_;
// Default setting for guiAvailable property.
private static boolean defaultGuiAvailable_ = true;
// Default setting for mustAddLanguageLibrary property.
private static boolean defaultMustAddLanguageLibrary_ = false;
// Default setting for mustUseSockets property.
private static boolean defaultMustUseSockets_ = false;
// Default setting for mustUseNetSockets property.
private static boolean defaultMustUseNetSockets_ = false;
// Default setting for mustUseSuppliedProfile property.
private static boolean defaultMustUseSuppliedProfile_ = false;
// Default setting for threadUsed property.
private static boolean defaultThreadUsed_ = true;
boolean skipSignonServer_ = false;
public String currentLib_ = "*CURUSR";
public String librariesForThread_ = "*CURUSR";
static
{
try
{
String s = System.getProperty("os.name");
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Detected os.name:", s);
if (s != null && s.equalsIgnoreCase("OS/400"))
{
String version = System.getProperty("os.version");
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Detected os.version:", version);
if (version != null)
{
char[] versionChars = version.toCharArray();
if (versionChars.length == 6)
{
int vrm = ((versionChars[1] & 0x000F) << 16) + ((versionChars[3] & 0x000F) << 8) + (versionChars[5] & 0x000F);
AS400.nativeVRM = new ServerVersion(vrm);
}
}
AS400.onAS400 = true;
}
} catch (SecurityException e) {
Trace.log(Trace.WARNING, "Error retrieving os.name:", e);
}
// Get the "default sign-on handler" property.
String propVal = SystemProperties.getProperty(SystemProperties.AS400_SIGNON_HANDLER);
if (propVal != null) {
try {
defaultSignonHandlerClass_ = Class.forName(propVal);
} catch (Exception e) {
Trace.log(Trace.WARNING, "Error retrieving default sign-on handler (specified by property):", e);
defaultSignonHandlerClass_ = ToolboxSignonHandler.class;
}
}
// Get the "GUI available" property.
propVal = SystemProperties.getProperty(SystemProperties.AS400_GUI_AVAILABLE);
if (propVal != null) {
try {
defaultGuiAvailable_ = Boolean.valueOf(propVal).booleanValue();
} catch (Exception e) {
Trace.log(Trace.WARNING, "Error retrieving guiAvailable property value:", e);
}
}
// Get the "must add language library" property.
propVal = SystemProperties.getProperty(SystemProperties.AS400_MUST_ADD_LANGUAGE_LIBRARY);
if (propVal != null) {
try {
defaultMustAddLanguageLibrary_ = Boolean.valueOf(propVal).booleanValue();
} catch (Exception e) {
Trace.log(Trace.WARNING, "Error retrieving mustAddLanguageLibrary property value:", e);
}
}
// Get the "must use sockets" property.
propVal = SystemProperties.getProperty(SystemProperties.AS400_MUST_USE_SOCKETS);
if (propVal != null) {
try {
defaultMustUseSockets_ = Boolean.valueOf(propVal).booleanValue();
} catch (Exception e) {
Trace.log(Trace.WARNING, "Error retrieving mustUseSockets property value:", e);
}
}
// Get the "must use net sockets" property.
propVal = SystemProperties.getProperty(SystemProperties.AS400_MUST_USE_NET_SOCKETS);
if (propVal != null) {
try {
defaultMustUseNetSockets_ = Boolean.valueOf(propVal).booleanValue();
} catch (Exception e) {
Trace.log(Trace.WARNING, "Error retrieving mustUseNetSockets property value:", e);
}
}
// Get the "must use supplied profile" property.
propVal = SystemProperties.getProperty(SystemProperties.AS400_MUST_USE_SUPPLIED_PROFILE);
if (propVal != null) {
try {
defaultMustUseSuppliedProfile_ = Boolean.valueOf(propVal).booleanValue();
} catch (Exception e) {
Trace.log(Trace.WARNING, "Error retrieving mustUseSuppliedProfile property value:", e);
}
}
// Get the "thread used" property.
propVal = SystemProperties.getProperty(SystemProperties.AS400_THREAD_USED);
if (propVal != null) {
try {
defaultThreadUsed_ = Boolean.valueOf(propVal).booleanValue();
} catch (Exception e) {
Trace.log(Trace.WARNING, "Error retrieving threadUsed property value:", e);
}
}
}
// System list: elements are 3 element Object[]: systemName, userId, credential vault
private static Vector systemList = new Vector();
// Default users is a hash from systemName to userId.
private static Hashtable defaultUsers = new Hashtable();
// Number of days previous to password expiration to start to warn user.
private static int expirationWarning = 7;
// Whether to use system value QPWDEXPWRN to calculate days previous to password expiration.
private boolean useSystemExpirationWarning_ = false;
private static int alreadyCheckedForMultipleVersions_ = 0;
// GSS Manager object, for Kerberos.
private static GSSManager gssManager_ = null;
// System name.
private String systemName_ = "";
// Flag indicating if system name refers to local system.
private boolean systemNameLocal_ = false;
// User ID.
private String userId_ = "";
// Credential vault used to store password, GSS token, identity token,
// or profile token. An AS400 object must always have its own copy of
// a credential vault (i.e. there must be a 1-to-1 correlation between
// AS400 objects and CredentialVault objects). Sharing a credential vault
// amongst two different AS400 objects is NEVER allowed.
// If you need to share the credential in the vault with another AS400 object,
// you must provide a copy of the credential vault. This is achieved using
// the clone() method provided by the CredentialVault class.
private transient CredentialVault credVault_; // never null after construction
// Additional authentication factor
private char[] additionalAuthenticationFactor_;
// GSS Credential object, for Kerberos. Type set to Object to prevent dependency on 1.4 JDK.
private transient GSSCredential gssCredential_ = null;
// GSS name string, for Kerberos.
private String gssName_ = "";
// How to use the GSS framework.
int gssOption_ = GSS_OPTION_FALLBACK;
// Proxy server system name.
private transient String proxyServer_ = "";
// Client side proxy connection information.
private transient Object proxyClientConnection_ = null; // Tolerate not having class ProxyClientConnection in the jar.
// This controls the prompting. If set to true, then prompting will occur during sign-on if needed. If set to false, no prompting will occur and all security errors are returned as exceptions.
private boolean guiAvailable_ = defaultGuiAvailable_;
// Use the password cache.
private boolean usePasswordCache_ = true;
// Use the default user.
private boolean useDefaultUser_ = true;
// Show the checkboxes on the password dialog.
private boolean showCheckboxes_ = true;
// Detect/prevent recursion when interacting with sign-on handler.
private boolean signingOn_ = false;
// SSL options, null value indicates SSL is not to be used. Options set in SecureAS400 subclass.
SSLOptions useSSLConnection_ = null;
// Flag that indicates if we must add the secondary language library to the library list.
private boolean mustAddLanguageLibrary_ = defaultMustAddLanguageLibrary_;
// Flag that indicates if we must use the host servers and no native optimizations.
private boolean mustUseSockets_ = defaultMustUseSockets_;
// Flag that indicates if we must use network sockets and not unix domain sockets.
private boolean mustUseNetSockets_ = defaultMustUseNetSockets_;
// Flag that indicates if we must not use the current profile.
private boolean mustUseSuppliedProfile_ = defaultMustUseSuppliedProfile_;
// Flag that indicates if we use threads in communication with the host servers.
private boolean threadUsed_ = defaultThreadUsed_;
// Locale object to use for determining NLV.
private Locale locale_ = Locale.getDefault();
// The NLV set or determined from the locale.
private String nlv_ = ExecutionEnvironment.getNlv(Locale.getDefault());
// The system's default time zone.
private transient TimeZone timezone_;
// Set of socket options to use when creating connections.
private SocketProperties socketProperties_ = new SocketProperties();
// No CCSID to start.
transient int ccsid_ = 0;
// List of connection event bean listeners.
private transient Vector connectionListeners_ = null; // Set on first add.
// Inner class that connects connection events that occur in the ImplRemote to this class.
private transient ConnectionListener dispatcher_ = null; // Set on first add.
// List of property change event bean listeners.
transient PropertyChangeSupport propertyChangeListeners_ = null; // Set on first add.
// List of vetoable change event bean listeners.
transient VetoableChangeSupport vetoableChangeListeners_ = null; // Set on first add.
// Flag for when object state is allowed to change.
transient boolean propertiesFrozen_ = false;
// Implementation object.
private transient AS400Impl impl_ = null;
// This object is created by the initial sign-on process. It contains the information from
// the retrieve sign-on information flow with the sign-on server.
private transient SignonInfo signonInfo_ = null;
// The IASP name used for the RECORDACCESS service.
private String ddmRDB_ = null;
// The sign-on handler for this object's instance.
private transient SignonHandler signonHandler_ = null;
private transient boolean handlerCanceled_ = false;
/* forcePrompt_ is a flag that tells AS400 to force prompt by displaying login dialog (actually the sign-on handler) prior to even trying to authenticate.
This is useful in cases where an application sends in incorrect dummy id/password and expects Toolbox to display the logon dialog.
In JDBC, we do some pre-validation of id/password. So JDBC may flag the id/password as invalid and then need
to let AS400 know that it just needs to display the logon dialog. */
private boolean forcePrompt_ = false;
private int validateSignonTimeOut_ = 0;
/**
* Constructs an AS400 object.
*
* If running on IBM i, the target is the local system. This has the same effect as using localhost
for
* the system name, *CURRENT for the user ID, and *CURRENT for the password.
*
* If running on another operating system, a sign-on prompt may be displayed. The user is then able to specify the
* system name, user ID, and password.
**/
public AS400()
{
super();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing AS400 object.");
construct();
systemNameLocal_ = resolveSystemNameLocal("");
proxyServer_ = resolveProxyServer(proxyServer_);
// Default to password authentication
credVault_ = new PasswordVault();
}
/**
* Constructs an AS400 object. It uses the specified system name.
*
* If running on IBM i to another system or to itself, the user ID and password of the current job are used.
*
* If running on another operating system, the user may be prompted for the user ID and password if a default user
* has not been established for this system name.
*
* @param systemName The name of the IBM i system. Use localhost
to access data locally.
**/
public AS400(String systemName)
{
super();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing AS400 object, system name: '" + systemName + "'");
if (systemName == null)
throw new NullPointerException("systemName");
construct();
systemName_ = systemName;
systemNameLocal_ = resolveSystemNameLocal(systemName);
proxyServer_ = resolveProxyServer(proxyServer_);
// Default to password authentication
credVault_ = new PasswordVault();
}
/**
* Constructs an AS400 object. It uses the specified system name and user ID. If the sign-on prompt is displayed,
* the user is able to specify the password. Note that the user ID may be overridden.
*
* @param systemName The name of the IBM i system. Use localhost
to access data locally.
* @param userId The user profile name to use to authenticate to the system. If running on IBM i, *CURRENT may
* be used to specify the current user ID.
* @exception ExtendedIllegalArgumentException If userId length is not valid.
**/
public AS400(String systemName, String userId)
{
super();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing AS400 object, system name: '" + systemName + "' user ID: '" + userId + "'");
if (systemName == null)
throw new NullPointerException("systemName");
if (userId == null)
throw new NullPointerException("userId");
if (userId.length() > 10)
throw new ExtendedIllegalArgumentException("userId (" + userId + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
construct();
systemName_ = systemName;
systemNameLocal_ = resolveSystemNameLocal(systemName);
if (isTurkish()) {
userId = userId.toUpperCase(Locale.ENGLISH);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "This system locale is Turkish, userId.toUpperCase(Locale.ENGLISH)");
}
userId_ = userId.toUpperCase();
proxyServer_ = resolveProxyServer(proxyServer_);
// Default to password authentication
credVault_ = new PasswordVault();
}
/**
* Constructs an AS400 object. It uses the specified system name and profile token.
*
* @param systemName The name of the IBM i system. Use localhost
to access data locally.
* @param profileToken The profile token to use to authenticate to the system.
**/
public AS400(String systemName, ProfileTokenCredential profileToken)
{
super();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing AS400 object with profile token, system name: '" + systemName + "'");
if (PASSWORD_TRACE) Trace.log(Trace.DIAGNOSTIC, "profile token: " + profileToken);
if (profileToken == null)
throw new NullPointerException("profileToken");
constructWithProfileToken(systemName, new ProfileTokenVault(profileToken));
}
/**
* Constructs an AS400 object. The specified ProfileTokenProvider is used. The token refresh threshold is determined
* by the ProfileTokenProvider.
*
* @param systemName The name of the IBM i system.
* @param tokenProvider The provider to use when a new profile token needs to be generated.
* @see #AS400(String,ProfileTokenProvider,int)
*/
public AS400(String systemName, ProfileTokenProvider tokenProvider) {
this(systemName, tokenProvider, null);
}
/**
* Constructs an AS400 object. The specified ProfileTokenProvider is used.
*
* @param systemName The name of the IBM i system.
* @param tokenProvider The provider to use when a new profile token needs to be generated.
* @param refreshThreshold The refresh threshold, in seconds, for the profile token. Used by the vault to manage the
* currency of the profile token to help ensure it remains current for an indefinite period
* of time.
* @see #AS400(String,ProfileTokenProvider)
*/
public AS400(String systemName, ProfileTokenProvider tokenProvider, int refreshThreshold) {
this(systemName, tokenProvider, Integer.valueOf(refreshThreshold));
}
private AS400(String systemName, ProfileTokenProvider tokenProvider, Integer refreshThreshold)
{
super();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing AS400 object with a profile token provider, system name: '" + systemName + "'");
if (tokenProvider == null)
throw new NullPointerException("tokenProvider");
if (PASSWORD_TRACE) Trace.log(Trace.DIAGNOSTIC, "profile token provider:", tokenProvider.getClass().getName());
constructWithProfileToken(systemName, (refreshThreshold != null)
? new ManagedProfileTokenVault(tokenProvider, refreshThreshold.intValue())
: new ManagedProfileTokenVault(tokenProvider));
}
/**
* Common code for constructing an AS400 object that uses profile token authentication
*/
private void constructWithProfileToken(String systemName, ProfileTokenVault credVault)
{
if (systemName == null)
throw new NullPointerException("systemName");
construct();
systemName_ = systemName;
systemNameLocal_ = resolveSystemNameLocal(systemName);
// Assumption: The caller of this method has ensured that the credential
// vault has been created and initialized correctly.
credVault_ = credVault;
proxyServer_ = resolveProxyServer(proxyServer_);
}
/**
* Constructs an AS400 object. It uses the specified system name, user ID, and password. No sign-on prompt is
* displayed unless the sign-on fails.
*
* @param systemName The name of the IBM i system. Use localhost
to access data locally.
* @param userId The user profile name to use to authenticate to the system. If running on IBM i, *CURRENT may
* be used to specify the current user ID.
* @param password The user profile password to use to authenticate to the system. If running on IBM i, CURRENT
* may be used to specify the current user ID.
* @exception ExtendedIllegalArgumentException If userId length is not valid.
* @deprecated Use AS400(String systemName, String userId, char[] password) instead
**/
@Deprecated
public AS400(String systemName, String userId, String password)
{
super();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing AS400 object with password, system name: '" + systemName + "' user ID: '" + userId + "'");
if (PASSWORD_TRACE) Trace.log(Trace.DIAGNOSTIC, "password: '" + password + "'");
if (systemName == null)
throw new NullPointerException("systemName");
if (userId == null)
throw new NullPointerException("userId");
if (userId.length() > 10)
throw new ExtendedIllegalArgumentException("userId (" + userId + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
char[] passwordChars = (password == null) ? null : password.toCharArray();
try
{
checkPasswordNullAndLength(passwordChars, "password");
construct();
systemName_ = systemName;
systemNameLocal_ = resolveSystemNameLocal(systemName);
if (isTurkish()) {
userId = userId.toUpperCase(Locale.ENGLISH);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "This system locale is Turkish, userId.toUpperCase(Locale.ENGLISH)");
}
userId_ = userId.toUpperCase();
credVault_ = new PasswordVault(passwordChars);
}
finally {
PasswordVault.clearArray(passwordChars);
}
proxyServer_ = resolveProxyServer(proxyServer_);
}
/**
* Constructs an AS400 object. It uses the specified system name, user ID, password, and additional authentication
* factor. No sign-on prompt is displayed unless the sign-on fails.
*
* @param systemName The name of the IBM i system. Use localhost
to access data locally.
* @param userId The user profile name to use to authenticate to the system. If running on IBM i,
* *CURRENT may be used to specify the current user ID.
* @param password The user profile password to use to authenticate to the system.
* @param additionalAuthFactor Additional authentication factor (or null if not providing one). The caller is
* responsible for clearing the password array to keep the password from residing in
* memory.
* @throws AS400SecurityException If a security or authority error occurs.
* @throws IOException If an error occurs while communicating with the system.
**/
public AS400(String systemName, String userId, char[] password, char[] additionalAuthFactor) throws AS400SecurityException, IOException
{
this(systemName, userId, password);
setAdditionalAuthenticationFactor(additionalAuthFactor);
}
/**
* Constructs an AS400 object. It uses the specified system name, user ID, and password. No sign-on prompt is
* displayed unless the sign-on fails.
*
* @param systemName The name of the IBM i system. Use localhost
to access data locally.
* @param userId The user profile name to use to authenticate to the system. If running on IBM i, *CURRENT may
* be used to specify the current user ID.
* @param password The user profile password to use to authenticate to the system. The caller is responsible for
* clearing the password array to keep the password from residing in memory.
* @exception ExtendedIllegalArgumentException If userId length is not valid.
**/
public AS400(String systemName, String userId, char[] password)
{
super();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing AS400 object with password, system name: '" + systemName + "' user ID: '" + userId + "'");
if (PASSWORD_TRACE) Trace.log(Trace.DIAGNOSTIC, "password: '" + new String(password) + "'");
if (systemName == null)
throw new NullPointerException("systemName");
if (userId == null)
throw new NullPointerException("userId");
if (userId.length() > 10)
throw new ExtendedIllegalArgumentException("userId (" + userId + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
checkPasswordNullAndLength(password, "password");
construct();
systemName_ = systemName;
systemNameLocal_ = resolveSystemNameLocal(systemName);
if (isTurkish()) {
userId = userId.toUpperCase(Locale.ENGLISH);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "This system locale is Turkish, userId.toUpperCase(Locale.ENGLISH)");
}
userId_ = userId.toUpperCase();
credVault_ = new PasswordVault(password);
proxyServer_ = resolveProxyServer(proxyServer_);
}
private static final String[] USRLIBL_SINGLE_VALUE = new String[]
{
"*CURSYSBAS",
"*CURUSR",
"*SYSVAL",
"*NONE"
};
public String aspName="";
/**
* Set ASP group for the AS400 connection to the Remote Command Host server. It calls SETASPGRP command to change
* the asp setting for corresponding CommandCall, ProgramCall and ServiceProgramCall in the same connection. Current
* library default is *CURUSR. Libraries for current thread default is *CURUSR. If an ASP group had already been
* set, it will remove the old ASP group and set the specified ASP group for the current thread. Once the specified
* ASP group has been set, all libraries in the independent ASPs in the ASP group are accessible and objects in
* those libraries can be referenced using regular library-qualified object name syntax.
*
* @param IASPGroup asp group name
* @throws AS400SecurityException If a security or authority error occurs.
* @throws ErrorCompletingRequestException If an error occurs before the request is completed.
* @throws IOException If an error occurs while communicating with the system.
* @throws InterruptedException If this thread is interrupted.
* @throws PropertyVetoException If the recipient wishes the property change to be rolled back.
*/
public void setIASPGroup(String IASPGroup) throws AS400SecurityException, ErrorCompletingRequestException, IOException, InterruptedException, PropertyVetoException
{
this.currentLib_ = "*CURUSR";
this.librariesForThread_ = "*CURUSR";
String SetASPGrp = "SETASPGRP ASPGRP("+ IASPGroup + ") CURLIB(*CURUSR) USRLIBL(*CURUSR)"; //@P2C Default value *CURSYSBAS will override the user profile/jobd set libs.
Trace.log(Trace.DIAGNOSTIC,"AS400 Call command of setaspgrp "+SetASPGrp);
CommandCall commandCall = new CommandCall(this);
if (commandCall.run(SetASPGrp) != true) {
Trace.log(Trace.ERROR, this,"Command SETASPGRP Failed with iasp "+IASPGroup);
}
else
aspName = IASPGroup;
}
/**
* Set ASP group for the AS400 connection to the Remote Command Host server. It calls SETASPGRP command to change
* the asp setting for corresponding CommandCall, ProgramCall and ServiceProgramCall in the same connection.
* Libraries for current thread default is *CURUSR. If an ASP group had already been set, it will remove the old ASP
* group and set the specified ASP group for the current thread. Once the specified ASP group has been set, all
* libraries in the independent ASPs in the ASP group are accessible and objects in those libraries can be
* referenced using regular library-qualified object name syntax.
*
* @param IASPGroup asp group name
* @param currentLib Current library which can be *CURSYSBAS, *CURUSR, *CRTDFT, name. If null or "" is set, default
* value *CURUSR is used.
* @throws AS400SecurityException If a security or authority error occurs.
* @throws ErrorCompletingRequestException If an error occurs before the request is completed.
* @exception ExtendedIllegalArgumentException If currentLib length is not valid.
* @throws IOException If an error occurs while communicating with the system.
* @throws InterruptedException If this thread is interrupted.
* @throws PropertyVetoException If the recipient wishes the property change to be rolled back.
*/
public void setIASPGroup(String IASPGroup, String currentLib) throws AS400SecurityException, ErrorCompletingRequestException, IOException, InterruptedException, PropertyVetoException
{
if(currentLib==null || currentLib.length()==0)
currentLib = "*CURUSR";
else if (currentLib.length() > 10)
{
Trace.log(Trace.ERROR, "Length of parameter 'currentLib' is not valid: '" + currentLib + "'");
throw new ExtendedIllegalArgumentException("setIASPGroup currentLib (" + currentLib + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
}
this.currentLib_ = currentLib;
this.librariesForThread_ = "*CURUSR";
String SetASPGrp = "SETASPGRP ASPGRP("+ IASPGroup + ") CURLIB("+currentLib+") USRLIBL(*CURUSR)"; //@P2C Default value *CURSYSBAS will override the user profile/jobd set libs.
Trace.log(Trace.DIAGNOSTIC,"Call command of setaspgrp "+SetASPGrp);
CommandCall commandCall = new CommandCall(this);
if (commandCall.run(SetASPGrp) != true) {
Trace.log(Trace.ERROR, this,"Command SETASPGRP Failed with iasp "+IASPGroup);
} else
aspName = IASPGroup;
}
/**
* Set ASP group for the AS400 connection to the Remote Command Host server. It calls SETASPGRP command to change
* the asp setting for corresponding CommandCall, ProgramCall and ServiceProgramCall in the same connection. If an
* ASP group had already been set, it will remove the old ASP group and set the specified ASP group for the current
* thread. Once the specified ASP group has been set, all libraries in the independent ASPs in the ASP group are
* accessible and objects in those libraries can be referenced using regular library-qualified object name syntax.
*
* @param IASPGroup asp group name
* @param currentLib Current library which can be *CURSYSBAS, *CURUSR, *CRTDFT, name. If null or "" is set,
* default value *CURUSR is used.
* @param librariesForThread Libraries for current thread with single value. If null or "" is set, default value
* *CURUSR is used.
* @throws AS400SecurityException If a security or authority error occurs.
* @throws ErrorCompletingRequestException If an error occurs before the request is completed.
* @exception ExtendedIllegalArgumentException If currentLib or librariesForThread lengths are not valid.
* @throws IOException If an error occurs while communicating with the system.
* @throws InterruptedException If this thread is interrupted.
* @throws PropertyVetoException If the recipient wishes the property change to be rolled back.
*/
public void setIASPGroup(String IASPGroup, String currentLib, String librariesForThread) throws AS400SecurityException, ErrorCompletingRequestException, IOException, InterruptedException, PropertyVetoException
{
if(currentLib==null || currentLib.length()==0)
currentLib = "*CURUSR";
else if (currentLib.length() > 10)
{
Trace.log(Trace.ERROR, "Length of parameter 'currentLib' is not valid: '" + currentLib + "'");
throw new ExtendedIllegalArgumentException("setIASPGroup currentLib (" + currentLib + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
}
if(librariesForThread==null || librariesForThread.length()==0)
librariesForThread = "*CURUSR";
else if (librariesForThread.length() > 10)
{
Trace.log(Trace.ERROR, "Length of parameter 'librariesForThread' is not valid: '" + librariesForThread + "'");
throw new ExtendedIllegalArgumentException("setIASPGroup librariesForThread (" + librariesForThread + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
}
this.currentLib_ = currentLib;
this.librariesForThread_ = librariesForThread;
String SetASPGrp = "SETASPGRP ASPGRP("+ IASPGroup + ") CURLIB("+currentLib+") USRLIBL("+librariesForThread+")"; //@P2C Default value *CURSYSBAS will override the user profile/jobd set libs.
Trace.log(Trace.DIAGNOSTIC,"Call command of setaspgrp "+SetASPGrp);
CommandCall commandCall = new CommandCall(this);
if (commandCall.run(SetASPGrp) != true) {
Trace.log(Trace.ERROR, this,"Command SETASPGRP Failed with iasp "+IASPGroup);
} else
aspName = IASPGroup;
}
/**
* Set ASP group for the AS400 connection to the Remote Command Host server. It calls SETASPGRP command to change
* the asp setting for corresponding CommandCall, ProgramCall and ServiceProgramCall in the same connection. If an
* ASP group had already been set, it will remove the old ASP group and set the specified ASP group for the current
* thread. Once the specified ASP group has been set, all libraries in the independent ASPs in the ASP group are
* accessible and objects in those libraries can be referenced using regular library-qualified object name syntax.
*
* @param IASPGroup asp group name
* @param currentLib Current library which can be *CURSYSBAS, *CURUSR, *CRTDFT, name. If null or "" is set,
* default value *CURUSR is used.
* @param librariesForThread Libraries for current thread. If null is set, default value *CURUSR is used. Up to 250
* libraries can be set.
* @throws AS400SecurityException If a security or authority error occurs.
* @throws ErrorCompletingRequestException If an error occurs before the request is completed.
* @throws IOException If an error occurs while communicating with the system.
* @throws InterruptedException If this thread is interrupted.
* @throws PropertyVetoException If the recipient wishes the property change to be rolled back.
*/
public void setIASPGroup(String IASPGroup, String currentLib, String[] librariesForThread) throws AS400SecurityException, ErrorCompletingRequestException, IOException, InterruptedException, PropertyVetoException
{
if(currentLib==null || currentLib.length()==0)
currentLib = "*CURUSR";
else if (currentLib.length() > 10)
{
Trace.log(Trace.ERROR, "Length of parameter 'currentLib' is not valid: '" + currentLib + "'");
throw new ExtendedIllegalArgumentException("setIASPGroup currentLib (" + currentLib + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
}
if(librariesForThread==null || librariesForThread.length==0)
librariesForThread = new String[]{"*CURUSR"};
else if(librariesForThread.length>1)
{
if(librariesForThread.length>250){
Trace.log(Trace.ERROR, this,"Up to 250 libraries can be set for SETASPGRP USRLIBL");
throw new ExtendedIllegalArgumentException("setIASPGroup Libraries for current thread librariesForThread(" + librariesForThread.length + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
}
else
for(int i=0;i 10)
{
Trace.log(Trace.ERROR, "Length of parameter in 'librariesForThread' is not valid: '" + value + "'");
throw new ExtendedIllegalArgumentException("setIASPGroup parameter in librariesForThread (" + value + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
}
value=value.toUpperCase();
if(value.equals(USRLIBL_SINGLE_VALUE[0]) || value.equals(USRLIBL_SINGLE_VALUE[1])|| value.equals(USRLIBL_SINGLE_VALUE[2]) || value.equals(USRLIBL_SINGLE_VALUE[3])){
Trace.log(Trace.ERROR, this,value+" must be only value for parameter USRLIBL.");
throw new ExtendedIllegalArgumentException("SETASPGRP USRLIBL parameter value (" + value + ")", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID);
}
}
}
this.currentLib_ = currentLib;
this.librariesForThread_ = "";
for(int i=0;i 10)
throw new ExtendedIllegalArgumentException("userId (" + userId + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
setAdditionalAuthenticationFactor(additionalAuthFactor);
construct();
systemName_ = systemName;
systemNameLocal_ = resolveSystemNameLocal(systemName);
if (isTurkish()) {
userId = userId.toUpperCase(Locale.ENGLISH);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "This system locale is Turkish, userId.toUpperCase(Locale.ENGLISH)");
}
userId_ = userId.toUpperCase();
// Create a copy of the supplied credential vault. This allows the AS400
// object to have its own credential vault object while making the vault
// contain the the same credential as the original vault we have been provided.
// It is VERY important that the copy of the vault contain the same credential
// as the original vault. This is because the Toolbox implementation has
// always allowed two AS400 objects to share a credential (i.e. two AS400
// objects can both share the same password credential). So we must maintain
// that behavior, but we need to do so using two different credential vaults,
// because each AS400 object must always have its very own credential vault.
credVault_ = pwVault.clone();
proxyServer_ = resolveProxyServer(proxyServer_);
}
/**
* Constructs an AS400 object. It uses the specified system name, user ID, and password. No sign-on prompt is
* displayed unless the sign-on fails.
*
* @param systemName The name of the IBM i system. Use localhost
to access data locally.
* @param userId The user profile name to use to authenticate to the system. If running on IBM i, *CURRENT may
* be used to specify the current user ID.
* @param password The user profile password to use to authenticate to the system. If running on IBM i, *CURRENT
* may be used to specify the current user ID.
* @param proxyServer The name and port of the proxy server in the format serverName[:port]
. If no port
* is specified, a default will be used.
* @exception ExtendedIllegalArgumentException If userId length is not valid.
* @deprecated Use AS400((String systemName, String userId, char[] password, String proxyServer) instead.
**/
@Deprecated
public AS400(String systemName, String userId, String password, String proxyServer)
{
super();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing AS400 object with password, system name: '" + systemName + "' user ID: '" + userId + "' proxy server: '" + proxyServer + "'");
if (PASSWORD_TRACE) Trace.log(Trace.DIAGNOSTIC, "password: '" + password + "'");
if (systemName == null)
throw new NullPointerException("systemName");
if (userId == null)
throw new NullPointerException("userId");
if (userId.length() > 10)
throw new ExtendedIllegalArgumentException("userId (" + userId + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
char[] passwordChars = (password == null) ? null : password.toCharArray();
try
{
checkPasswordNullAndLength(passwordChars, "password");
if (proxyServer == null)
throw new NullPointerException("proxyServer");
construct();
systemName_ = systemName;
systemNameLocal_ = resolveSystemNameLocal(systemName);
if (isTurkish()) {
userId = userId.toUpperCase(Locale.ENGLISH);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "This system locale is Turkish, userId.toUpperCase(Locale.ENGLISH)");
}
userId_ = userId.toUpperCase();
credVault_ = new PasswordVault(passwordChars);
}
finally {
PasswordVault.clearArray(passwordChars);
}
proxyServer_ = resolveProxyServer(proxyServer);
}
/**
* Constructs an AS400 object. It uses the specified system name, user ID, and password. No sign-on prompt is
* displayed unless the sign-on fails.
*
* @param systemName The name of the IBM i system. Use localhost
to access data locally.
* @param userId The user profile name to use to authenticate to the system. If running on IBM i, *CURRENT may
* be used to specify the current user ID.
* @param password The user profile password to use to authenticate to the system. The caller is responsible fore
* clearing sensitive data from password after the constructor runs.
* @param proxyServer The name and port of the proxy server in the format serverName[:port]
. If no port
* is specified, a default will be used.
* @exception ExtendedIllegalArgumentException If userId length is not valid.
**/
public AS400(String systemName, String userId, char[] password, String proxyServer)
{
super();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing AS400 object with password, system name: '" + systemName + "' user ID: '" + userId + "' proxy server: '" + proxyServer + "'");
if (systemName == null)
throw new NullPointerException("systemName");
if (userId == null)
throw new NullPointerException("userId");
if (userId.length() > 10)
throw new ExtendedIllegalArgumentException("userId (" + userId + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
checkPasswordNullAndLength(password, "password");
if (proxyServer == null)
throw new NullPointerException("proxyServer");
construct();
systemName_ = systemName;
systemNameLocal_ = resolveSystemNameLocal(systemName);
if (isTurkish()) {
userId = userId.toUpperCase(Locale.ENGLISH);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "This system locale is Turkish, userId.toUpperCase(Locale.ENGLISH)");
}
userId_ = userId.toUpperCase();
credVault_ = new PasswordVault(password);
proxyServer_ = resolveProxyServer(proxyServer);
}
/**
* Constructs an AS400 object. This does not create a clone. The new AS400 object will
* uses the same system name, user ID, and other properties of the passed-in AS400 object,
* enabling the new object to generally behave in a similar manner as the passed-in AS400 object.
*
* Notes:
*
* - Host server connections are not shared between the passed-in AS400 object and the new AS400 object, except
* for the HOSTCNN service connection, which is shared as long as the authentication credentials
* stay the same.
*
- Properties that are not propagated to the new AS400 object include event listeners (connection, property change,
* vetoable property change.). In addition, you will need to call the {@link #setStayAlive(long)} method on the new
* AS400 object if you want the feature enabled.
*
*
* @param system A previously instantiated AS400 object.
**/
public AS400(AS400 system)
{
super();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing AS400 object, system: " + system);
if (system == null)
throw new NullPointerException("system");
construct();
systemName_ = system.systemName_;
systemNameLocal_ = system.systemNameLocal_;
userId_ = system.userId_;
// Create a copy of the supplied credential vault. This allows the AS400
// object to have its own credential vault object while making the vault
// contain the the same credential as the original vault we have been provided.
// It is VERY important that the copy of the vault contain the same credential
// as the original vault. This is because the Toolbox implementation has
// always allowed two AS400 objects to share a credential (i.e. two AS400
// objects can both share the same password credential). So we must maintain
// that behavior, but we need to do so using two different credential vaults,
// because each AS400 object must always have its very own credential vault.
credVault_ = (CredentialVault)system.credVault_.clone();
additionalAuthenticationFactor_ = system.additionalAuthenticationFactor_;
gssCredential_ = system.gssCredential_;
gssName_ = system.gssName_;
gssOption_ = system.gssOption_;
proxyServer_ = system.proxyServer_;
// proxyClientConnection_ is not copied.
guiAvailable_ = system.guiAvailable_;
usePasswordCache_ = system.usePasswordCache_;
useDefaultUser_ = system.useDefaultUser_;
showCheckboxes_ = system.showCheckboxes_;
// If passed in system has SSL options, deep copy them if this instance is secure
if (system.isSecure())
useSSLConnection_= new SSLOptions(system.useSSLConnection_);
mustAddLanguageLibrary_ = system.mustAddLanguageLibrary_;
mustUseSockets_ = system.mustUseSockets_;
mustUseNetSockets_ = system.mustUseNetSockets_;
mustUseSuppliedProfile_ = system.mustUseSuppliedProfile_;
threadUsed_ = system.threadUsed_;
locale_ = system.locale_;
nlv_ = system.nlv_;
socketProperties_.copyValues(system.socketProperties_);
ccsid_ = system.ccsid_;
// connectionListeners_ is not copied.
// dispatcher_ is not copied.
// propertyChangeListeners_ is not copied.
// vetoableChangeListeners_ is not copied.
// propertiesFrozen_ is not copied.
// impl_ is not copied.
// signonInfo_ is not copied.
ddmRDB_ = system.ddmRDB_;
if (system.impl_ != null && system.impl_.isConnected(AS400.HOSTCNN))
{
impl_ = (AS400Impl)loadImpl2("com.ibm.as400.access.AS400ImplRemote", "com.ibm.as400.access.AS400ImplProxy");
signonInfo_ = impl_.setState(system.impl_, credVault_);
// Do not freeze properties as these need to be changed for new JDBC connections.
}
}
/**
* Returns a new instance of an AS400 object.
*
* If running on IBM i, the target is the local system. This has the same effect as using localhost
for
* the system name, *CURRENT for the user ID, and *CURRENT for the password.
*
* If running on another operating system, a sign-on prompt may be displayed. The user is then able to specify the
* system name, user ID, and password.
* @param useSSL Whether or not the new AS400 object should use secure connections when communicating with the
* host servers.
* @return AS400 object.
**/
public static AS400 newInstance(boolean useSSL)
{
return (useSSL) ? new SecureAS400()
: new AS400();
}
/**
* Returns a new instance of an AS400 object. It uses the specified system name.
*
* If running on IBM i to another system or to itself, the user ID and password of the current job are used.
*
* If running on another operating system, the user may be prompted for the user ID and password if a default user
* has not been established for this system name.
*
* @param useSSL Whether or not the new AS400 object should use secure connections when communicating with the
* host servers.
* @param systemName The name of the IBM i system. Use localhost
to access data locally.
* @return AS400 object.
**/
public static AS400 newInstance(boolean useSSL, String systemName)
{
return (useSSL) ? new SecureAS400(systemName)
: new AS400(systemName);
}
/**
* Returns a new instance of an AS400 object. It uses the specified system name, and user ID. When the sign-on
* prompt is displayed, the user is able to specify the password. Note that the user ID may be overridden in the
* AS400 object.
*
* @param useSSL Whether or not the new AS400 object should use secure connections when communicating with the
* host servers.
* @param systemName The name of the IBM i system. Use localhost
to access data locally.
* @param userId The user profile name to use to authenticate to the system. If running on IBM i, *CURRENT may
* be used to specify the current user ID.
* @return AS400 object.
* @throws IOException If an error occurs while communicating with the system.
* @throws AS400SecurityException If a security or authority error occurs.
**/
public static AS400 newInstance(boolean useSSL, String systemName, String userId) throws IOException, AS400SecurityException
{
return (useSSL) ? new SecureAS400(systemName, userId)
: new AS400(systemName, userId);
}
/**
* Returns a new instance of an AS400 object. It uses the specified system name, user ID, password, and additional
* authentication factor. No sign-on prompt is displayed unless the sign-on fails.
*
* @param useSSL Whether or not the new AS400 object should use secure connections when communicating
* with the host servers.
* @param systemName The name of the IBM i system. Use localhost
to access data locally.
* @param userId The user profile name to use to authenticate to the system. If running on IBM i,
* *CURRENT may be used to specify the current user ID.
* @param password The user profile password to use to authenticate to the system. The caller is
* responsible for clearing the password array to keep the password from residing in
* memory.
* @param additionalAuthFactor Additional authentication factor (or null if not providing one).
* @return AS400 object.
* @throws IOException If an error occurs while communicating with the system.
* @throws AS400SecurityException If a security or authority error occurs.
**/
public static AS400 newInstance(boolean useSSL, String systemName, String userId, char[] password, char[] additionalAuthFactor) throws IOException, AS400SecurityException
{
return (useSSL) ? new SecureAS400(systemName, userId, password, additionalAuthFactor)
: new AS400(systemName, userId, password, additionalAuthFactor);
}
/**
* Returns a new instance of an AS400 object. It uses the specified system name, user ID, and password. No sign-on
* prompt is displayed unless the sign-on fails.
*
* @param useSSL Whether or not the new AS400 object should use secure connections when communicating with the
* host servers.
* @param systemName The name of the IBM i system. Use localhost
to access data locally.
* @param userId The user profile name to use to authenticate to the system. If running on IBM i, *CURRENT may
* be used to specify the current user ID.
* @param password The user profile password to use to authenticate to the system. The caller is responsible fore
* clearing sensitive data from password after the constructor runs.
* @param proxyServer The name and port of the proxy server in the format serverName[:port]
. If no port
* is specified, a default will be used.
* @return AS400 object.
**/
public static AS400 newInstance(boolean useSSL, String systemName, String userId, char[] password, String proxyServer)
{
return (useSSL) ? new SecureAS400(systemName, userId, password, proxyServer)
: new AS400(systemName, userId, password, proxyServer);
}
/**
* Returns a new instance of an AS400 object. It uses the specified system name and profile token.
*
* @param useSSL Whether or not the new AS400 object should use secure connections when communicating with the
* host servers.
* @param systemName The name of the IBM i system. Use localhost
to access data locally.
* @param profileToken The profile token to use to authenticate to the system.
* @return AS400 object.
**/
public static AS400 newInstance(boolean useSSL, String systemName, ProfileTokenCredential profileToken)
{
return (useSSL) ? new SecureAS400(systemName, profileToken)
: new AS400(systemName, profileToken);
}
/**
* Returns a new instance of an AS400 object. It uses the same system name and user ID. This does not create a
* clone. The new object has the same behavior, but results in a new set of socket connections.
*
* @param useSSL Whether or not the new AS400 object should use secure connections when communicating with the host
* server.
* @param system A previously instantiated AS400 object.
* @return AS400 object.
**/
public static AS400 newInstance(boolean useSSL, AS400 system)
{
return (useSSL) ? new SecureAS400(system)
: new AS400(system);
}
/**
* Adds a listener to be notified when a connection event occurs.
*
* @param listener The listener object.
**/
public void addConnectionListener(ConnectionListener listener)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Adding connection listener.");
if (listener == null)
{
throw new NullPointerException("listener");
}
synchronized (this)
{
// If first add.
if (connectionListeners_ == null)
{
connectionListeners_ = new Vector();
dispatcher_ = new ConnectionListener()
{
public void connected(ConnectionEvent event) {
fireConnectEvent(event, true);
}
public void disconnected(ConnectionEvent event) {
fireConnectEvent(event, false);
}
};
}
// If this is the first add and we are already connected.
if (impl_ != null && connectionListeners_.isEmpty())
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Enabling connection listener dispatcher.");
impl_.addConnectionListener(dispatcher_);
}
connectionListeners_.addElement(listener);
}
}
/**
* Validates the user ID and password, and if successful, adds the information to the password cache.
*
* @param systemName The name of the IBM i system.
* @param userId The user profile name.
* @param password The user profile password.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
* @deprecated Use addPasswordCacheEntry(String systemName, String userId, char[] password) instead
**/
public static void addPasswordCacheEntry(String systemName, String userId, String password) throws AS400SecurityException, IOException
{
addPasswordCacheEntry(systemName, userId, (password == null) ? (char[])null : password.toCharArray(), false);
}
/**
* Validates the user ID and password, and if successful, adds the information to the password cache.
*
* @param systemName The name of the IBM i system.
* @param userId The user profile name.
* @param password The user profile password.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
**/
public static void addPasswordCacheEntry(String systemName, String userId, char[] password) throws AS400SecurityException, IOException
{
addPasswordCacheEntry(systemName, userId, password, false);
}
/**
* Validates the user ID and password, and if successful, adds the information to the password cache.
*
* @param systemName The name of the IBM i system.
* @param userId The user profile name.
* @param password The user profile password.
* @param useSSL Whether or not secure connections should be used when communicating with the host servers.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
**/
public static void addPasswordCacheEntry(String systemName, String userId, char[] password, boolean useSSL) throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Adding password cache entry, system name: '" + systemName + "' user ID: '" + userId + "'" + " useSSL: " + useSSL);
addPasswordCacheEntry((useSSL) ? new SecureAS400(systemName, userId, password) : new AS400(systemName, userId, password));
}
/**
* Validates the user ID and password, and if successful, adds the information to the password cache.
*
* @param systemName The name of the IBM i system.
* @param userId The user profile name.
* @param password The user profile password.
* @param proxyServer The name and port of the proxy server in the format serverName[:port]
. If no port
* is specified, a default will be used.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
* @deprecated Use addPasswordCacheEntry(String systemName, String userId, char[] password, String proxyServer)
* instead.
**/
@Deprecated
public static void addPasswordCacheEntry(String systemName, String userId, String password, String proxyServer) throws AS400SecurityException, IOException
{
addPasswordCacheEntry(systemName, userId, (password == null) ? (char[])null : password.toCharArray(), proxyServer, false);
}
/**
* Validates the user ID and password, and if successful, adds the information to the password cache.
*
* @param systemName The name of the IBM i system.
* @param userId The user profile name.
* @param password The user profile password.
* @param proxyServer The name and port of the proxy server in the format serverName[:port]
. If no port
* is specified, a default will be used.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
**/
public static void addPasswordCacheEntry(String systemName, String userId, char[] password, String proxyServer) throws AS400SecurityException, IOException
{
addPasswordCacheEntry(systemName, userId, password, proxyServer, false);
}
/**
* Validates the user ID and password, and if successful, adds the information to the password cache.
*
* @param systemName The name of the IBM i system.
* @param userId The user profile name.
* @param password The user profile password.
* @param proxyServer The name and port of the proxy server in the format serverName[:port]
. If no port
* is specified, a default will be used.
* @param useSSL Whether or not secure connections should be used when communicating with the host servers.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
**/
public static void addPasswordCacheEntry(String systemName, String userId, char[] password, String proxyServer, boolean useSSL) throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Adding password cache entry, system name: '" + systemName + "' user ID: '" + userId + "' proxy server: '" + proxyServer + "'" + "' useSSL: '" + useSSL);
addPasswordCacheEntry((useSSL) ? new SecureAS400(systemName, userId, password, proxyServer) : new AS400(systemName, userId, password, proxyServer));
}
private static void addPasswordCacheEntry(AS400 system) throws AS400SecurityException, IOException
{
system.validateSignon(); // Exception thrown if info not valid.
setCacheEntry(system.systemName_, system.userId_, system.credVault_);
}
/**
* Adds a listener to be notified when the value of any property is changed.
*
* @param listener The listener object.
**/
public void addPropertyChangeListener(PropertyChangeListener listener)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Adding property change listener.");
if (listener == null)
throw new NullPointerException("listener");
synchronized (this)
{
// If first add.
if (propertyChangeListeners_ == null)
propertyChangeListeners_ = new PropertyChangeSupport(this);
propertyChangeListeners_.addPropertyChangeListener(listener);
}
}
/**
* Adds a listener to be notified when the value of any constrained property is changed. The vetoableChange method
* will be called.
*
* @param listener The listener object.
**/
public void addVetoableChangeListener(VetoableChangeListener listener)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Adding vetoable change listener.");
if (listener == null)
throw new NullPointerException("listener");
synchronized (this)
{
// If first add.
if (vetoableChangeListeners_ == null)
vetoableChangeListeners_ = new VetoableChangeSupport(this);
vetoableChangeListeners_.addVetoableChangeListener(listener);
}
}
/**
* Indicates if properties are frozen. If this is true, property changes should not be made. Properties are not the
* same thing as attributes. Properties are basic pieces of information which must be set to make the object usable,
* such as the system name, user ID or other properties that identify the resource.
*
* @return true if properties are frozen, false otherwise.
**/
public boolean arePropertiesFrozen()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Checking if properties are frozen:", propertiesFrozen_);
return propertiesFrozen_;
}
/**
* Checks whether an additional authentication factor is accepted for the given system. The communications with the
* host server is done over a secure channel if the AS400 object was created to use SSL; otherwise, the
* communications with the host server is done over an unsecure channel.
*
* @return whether the server accepts the additional authentication factor
* @exception IOException If an error occurs while communicating with the system.
* @throws AS400SecurityException If an error occurs exchanging client/server information
**/
public boolean isAdditionalAuthenticationFactorAccepted() throws IOException, AS400SecurityException {
return isAdditionalAuthenticationFactorAccepted(getSystemName(), isSecure());
}
/**
* Checks whether an additional authentication factor is accepted for the given system
*
* @param systemName The IP address or hostname of the target system
* @param useSSL Whether or not secure connections should be used when communicating with the host servers.
* @return whether the server accepts the additional authentication factor
* @exception IOException If an error occurs while communicating with the system.
* @throws AS400SecurityException If an error occurs exchanging client/server information
**/
public static boolean isAdditionalAuthenticationFactorAccepted(String systemName, boolean useSSL) throws IOException, AS400SecurityException {
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting whether additional factor accepted: " + systemName + ", use SSL:", useSSL);
return AS400ImplRemote.getAdditionalAuthenticationIndicator(systemName, useSSL);
}
/**
* Checks whether an additional authentication factor is accepted for the given system
*
* @param systemName The IP address or hostname of the target system
* @return whether the server accepts the additional authentication factor
* @exception IOException If an error occurs while communicating with the system.
* @throws AS400SecurityException If an error occurs exchanging client/server information
* @deprecated Use {@link #isAdditionalAuthenticationFactorAccepted(String, boolean)}
**/
@Deprecated
public static boolean isAdditionalAuthenticationFactorAccepted(String systemName) throws IOException, AS400SecurityException {
return isAdditionalAuthenticationFactorAccepted(systemName, false);
}
/**
* Authenticate the user ID and password on the system and adds to the signon-list. This means that authentication
* is performed using the AS400 object instance for which this method is invoked - a new AS400 object is not created
* to do the authentication (unlike the other authenticate(String, String) or validateSignon() methods).
*
* If the AS400 object has previously been authenticated, either by using authenticate() or indirectly such as when
* establishing a connection to a host server, and if any of the setter methods are used after the authentication to
* change credentials, such as user ID or system name, the AS400.HOSTCNN and/or AS400.SIGNON server connections, if
* they exist, may be discarded if the change is different than what was previously used in the authentication
* process.
*
* Note: This will return true if the information is successfully validated. An unsuccessful validation will
* cause an exception to be thrown, false is never returned.
*
* Note:If an additional authentication factor has been set in the AS400 object, it is used.
*
* @return true if successful.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception ExtendedIllegalStateException If system name or user ID not set.
* @exception IOException If an error occurs while communicating with the system.
**/
public boolean authenticate() throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Authenticating signon.");
if (systemName_.length() == 0 && !systemNameLocal_)
{
Trace.log(Trace.ERROR, "Cannot authenticate signon before system name is set.");
throw new ExtendedIllegalStateException("systemName", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
userId_ = resolveUserId(userId_);
if (userId_.length() == 0)
{
Trace.log(Trace.ERROR, "Cannot authenticate signon before user ID is set.");
throw new ExtendedIllegalStateException("userId", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
return validateSignon(false, userId_, credVault_, additionalAuthenticationFactor_);
}
/**
* Authenticates the user profile name and user profile password.
*
* This method is functionally equivalent to the validateSignon() method, except it does not alter the user
* profile assigned to this object, impact the status of existing connections, or otherwise impact the user and
* authorities on which the application is running.
*
* The system name needs to be set prior to calling this method.
*
* Note: Providing an incorrect password increments the number of failed sign-on attempts for the user
* profile, and can result in the profile being disabled.
*
* Note: This will return true if the information is successfully validated. An unsuccessful validation will
* cause an exception to be thrown, false is never returned.
*
* @param userId The user profile name.
* @param password The user profile password.
* @return true if successful.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
* @deprecated Using a String as a password is insecure.
**/
@Deprecated
public boolean authenticate(String userId, String password) throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Authenticating signon information:", userId);
return validateSignon(userId, password);
}
/**
* Authenticates the user profile name and user profile password.
*
* This method is functionally equivalent to the validateSignon() method, except it does not alter the user
* profile assigned to this object, impact the status of existing connections, or otherwise impact the user and
* authorities on which the application is running.
*
* The system name needs to be set prior to calling this method.
*
* Note: Providing an incorrect password increments the number of failed sign-on attempts for the user
* profile, and can result in the profile being disabled.
*
* Note: This will return true if the information is successfully validated. An unsuccessful validation will
* cause an exception to be thrown, false is never returned.
*
* @param userId The user profile name.
* @param password The user profile password.
* @return true if successful.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
**/
public boolean authenticate(String userId, char[] password) throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Authenticating signon information:", userId);
return validateSignon(userId, password);
}
// Only load native version once.
private static int nativeVersion = -1;
private static int getNativeVersion()
{
try
{
if (AS400.nativeVersion == -1)
AS400.nativeVersion = Class.forName("com.ibm.as400.access.NativeVersion").newInstance().hashCode();
}
catch (ClassNotFoundException e)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Not using native optimizations; class 'NativeVersion' is not found.");
AS400.nativeVersion = 0;
}
catch (Exception e)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Not using native optimizations; unexpected exception while loading native version:", e);
AS400.nativeVersion = 0;
}
return AS400.nativeVersion;
}
/**
* Indicates if this AS400 object is enabled to exploit Toolbox native optimizations. This requires that the native
* optimization classes are available on the classpath, and this AS400 object represents the local system and is
* configured to allow the native optimizations to be used. Note: If the authentication scheme is other than
* {@link #AUTHENTICATION_SCHEME_PASSWORD AUTHENTICATION_SCHEME_PASSWORD}, native optimizations will not be used.
*
* @return true if the native optimizations can be used; false otherwise.
* @see #isLocal
* @see #isMustUseSockets
* @see #getAuthenticationScheme
**/
public boolean canUseNativeOptimizations()
{
if (AS400.onAS400 && !mustUseSockets_ && systemNameLocal_ && proxyServer_.length() == 0
&& credVault_.getType() == AUTHENTICATION_SCHEME_PASSWORD && getNativeVersion() == 2)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Using native optimizations.");
return true;
}
if (Trace.traceOn_)
{
Trace.log(Trace.DIAGNOSTIC, "Not using native optimizations. Reason follows:");
if (!AS400.onAS400) Trace.log(Trace.DIAGNOSTIC, " onAS400:", AS400.onAS400);
if (mustUseSockets_) Trace.log(Trace.DIAGNOSTIC, " mustUseSockets:", mustUseSockets_);
if (!systemNameLocal_) Trace.log(Trace.DIAGNOSTIC, " systemNameLocal:", systemNameLocal_);
if (proxyServer_.length() != 0) Trace.log(Trace.DIAGNOSTIC, " proxyServer:", proxyServer_);
int credType = credVault_.getType();
if (credType != AUTHENTICATION_SCHEME_PASSWORD) {
// Design note: For various reasons (such as lack of requirement, and potential complications
// when swapping during a token-based session), the Toolbox has never supported staying
// on-thread when using profile tokens or other non-password based authentication schemes.
Trace.log(Trace.DIAGNOSTIC, " authenticationScheme:", credType + " ("+credTypeToString(credType)+")");
}
if (getNativeVersion() != 2) Trace.log(Trace.DIAGNOSTIC, " nativeVersion:", getNativeVersion());
}
return false;
}
private static final String credTypeToString(int credType)
{
String result;
switch (credType)
{
case AUTHENTICATION_SCHEME_PASSWORD :
result = "password";
break;
case AUTHENTICATION_SCHEME_GSS_TOKEN :
result = "GSS token";
break;
case AUTHENTICATION_SCHEME_PROFILE_TOKEN :
result = "profile token";
break;
case AUTHENTICATION_SCHEME_IDENTITY_TOKEN :
result = "identity token";
break;
default :
result = "unrecognized";
}
return result;
}
/**
* Changes the user profile password. The system name and user profile name need to be set prior to calling this
* method.
*
* @param oldPassword The old user profile password.
* @param newPassword The new user profile password.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
* @deprecated Use changePassword(char[] oldPassword, char[] newPassword) instead
**/
@Deprecated
public void changePassword(String oldPassword, String newPassword) throws AS400SecurityException, IOException
{
char[] oldPasswordChars = (oldPassword == null) ? null : oldPassword.toCharArray();
char[] newPasswordChars = (newPassword == null) ? null : newPassword.toCharArray();
try {
changePassword(oldPasswordChars, newPasswordChars, null);
}
finally {
PasswordVault.clearArray(oldPasswordChars);
PasswordVault.clearArray(newPasswordChars);
}
}
/**
* Changes the user profile password. The system name and user profile name need to be set prior to calling this
* method.
*
* @param oldPassword The old user profile password.
* @param newPassword The new user profile password.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
**/
public void changePassword(char[] oldPassword, char[] newPassword) throws AS400SecurityException, IOException
{
changePassword(oldPassword, newPassword, null);
}
/**
* Changes the user profile password. The system name and user profile name need to be set prior to calling this
* method.
*
* @param oldPassword The old user profile password.
* @param newPassword The new user profile password.
* @param additionalAuthFactor Additional authentication factor (or null if not providing one).
* @exception AS400SecurityException If a security or authority error occurs.
* @exception ExtendedIllegalStateException If system name or user ID not set.
* @exception IOException If an error occurs while communicating with the system.
**/
public void changePassword(char[] oldPassword, char[] newPassword, char[] additionalAuthFactor) throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Changing password.");
if (PASSWORD_TRACE)
{
Trace.log(Trace.DIAGNOSTIC, "oldPassword: '" + new String(oldPassword) + "'");
Trace.log(Trace.DIAGNOSTIC, "newPassword: '" + new String(newPassword) + "'");
}
checkPasswordNullAndLength(oldPassword, "oldPassword");
checkPasswordNullAndLength(newPassword, "newPassword");
if (systemName_.length() == 0 && !systemNameLocal_)
{
Trace.log(Trace.ERROR, "Cannot change password before system name is set.");
throw new ExtendedIllegalStateException("systemName", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
if (additionalAuthFactor != null && additionalAuthFactor.length > ProfileTokenCredential.MAX_ADDITIONALAUTHENTICATIONFACTOR_LENGTH)
throw new ExtendedIllegalArgumentException("additionalAuthFactor", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
userId_ = resolveUserId(userId_);
if (userId_.length() == 0)
{
Trace.log(Trace.ERROR, "Cannot change password before user ID is set.");
throw new ExtendedIllegalStateException("userId", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
chooseImpl();
// Synchronize to protect sign-on information.
synchronized (this)
{
byte[] proxySeed = new byte[9];
CredentialVault.rng.nextBytes(proxySeed);
byte[] remoteSeed = impl_.exchangeSeed(proxySeed);
if (PASSWORD_TRACE)
{
Trace.log(Trace.DIAGNOSTIC, "AS400 object proxySeed:", proxySeed);
Trace.log(Trace.DIAGNOSTIC, "AS400 object remoteSeed:", remoteSeed);
}
// Note that in this particular case it is OK to just pass byte arrays
// instead of credential vaults. That is because we have the clear text
// passwords, so all we need to do is encode them and send them over
// to the impl. After the password has been changed, we will update
// our own credential vault with the new password, and create ourselves
// the appropriate type of credential vault to store the password in.
byte[] oldbytes = null;
byte[] newbytes = null;
try
{
oldbytes = BinaryConverter.charArrayToByteArray(oldPassword);
newbytes = BinaryConverter.charArrayToByteArray(newPassword);
byte[] encodeOldBytes = CredentialVault.encode(proxySeed, remoteSeed, oldbytes);
byte[] encodeNewBytes = CredentialVault.encode(proxySeed, remoteSeed, newbytes);
signonInfo_ = impl_.changePassword(systemName_, systemNameLocal_, userId_,
encodeOldBytes, encodeNewBytes, additionalAuthFactor);
}
finally {
CredentialVault.clearArray(oldbytes);
CredentialVault.clearArray(newbytes);
}
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Password changed successfully.");
// Update credential vault with new password.
credVault_.empty();
credVault_ = new PasswordVault(newPassword);
}
}
// Choose between remote and proxy implementation objects, set state information into remote implementation object.
// Synchronized to protect impl_ and propertiesFrozen_ instance variables. This method can safely be called multiple
// times because it checks its state before performing the code.
private synchronized void chooseImpl()
{
if (impl_ == null)
{
impl_ = (AS400Impl)loadImpl2("com.ibm.as400.access.AS400ImplRemote", "com.ibm.as400.access.AS400ImplProxy");
// If there is a connection listener. Connect the remote implementation connection events to this object.
if (connectionListeners_ != null && !connectionListeners_.isEmpty())
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Enabling connection listener dispatcher.");
impl_.addConnectionListener(dispatcher_);
}
}
if (!propertiesFrozen_)
{
impl_.setState(useSSLConnection_, canUseNativeOptimizations(), threadUsed_, ccsid_, nlv_,
socketProperties_, ddmRDB_, mustUseNetSockets_, mustUseSuppliedProfile_, mustAddLanguageLibrary_);
propertiesFrozen_ = true;
}
impl_.setBidiStringType(getBidiStringType());
impl_.setAdditionalAuthenticationFactor(additionalAuthenticationFactor_);
}
/**
* Clears the password cache for all systems within this Java virtual machine.
**/
public static void clearPasswordCache()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Clearing password cache.");
synchronized (AS400.systemList)
{
AS400.systemList.removeAllElements();
}
}
/**
* Clears all the passwords that are cached for the given system name within this Java virtual machine.
*
* @param systemName The name of the IBM i system.
**/
public static void clearPasswordCache(String systemName)
{
String longName = null;
boolean isLocalHost = false;
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Clearing password cache, system name:", systemName);
if (systemName == null)
throw new NullPointerException("systemName");
systemName = resolveSystem(systemName);
boolean localHost = systemName.equals("localhost");
if (localHost)
{
isLocalHost = true;
try {
systemName = InetAddress.getLocalHost().getHostName();
} catch (Exception e) { /* ignore */ }
}
int dotIndex = systemName.indexOf(".");
if (dotIndex > 0) {
longName = systemName;
systemName = systemName.substring(0,dotIndex);
}
synchronized (AS400.systemList)
{
for (int i = AS400.systemList.size() - 1; i >= 0; i--)
{
String elementName = (String)((Object[])AS400.systemList.elementAt(i))[0];
if (systemName.equalsIgnoreCase(elementName))
AS400.systemList.removeElementAt(i);
else if (isLocalHost && "localhost".equalsIgnoreCase(elementName))
AS400.systemList.removeElementAt(i);
else if ((longName != null) && longName.equalsIgnoreCase(elementName))
AS400.systemList.removeElementAt(i);
}
}
}
/**
* Connects to a service. Security is validated and a connection is established.
*
* Services typically connect implicitly; therefore, this method does not have to be called to use a service. This
* method can be used to control when the connection is established.
*
* @param service The name of the service. Valid services are:
*
* - {@link #FILE FILE} - IFS file classes.
*
- {@link #PRINT PRINT} - print classes.
*
- {@link #COMMAND COMMAND} - command and program call classes.
*
- {@link #DATAQUEUE DATAQUEUE} - data queue classes.
*
- {@link #DATABASE DATABASE} - JDBC classes.
*
- {@link #RECORDACCESS RECORDACCESS} - record level access classes.
*
- {@link #CENTRAL CENTRAL} - license management classes.
*
- {@link #SIGNON SIGNON} - sign-on classes.
*
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
**/
public void connectService(int service) throws AS400SecurityException, IOException {
connectService(service, -1);
}
/**
* Connects to a service. Security is validated and a connection is established.
*
* Services typically connect implicitly; therefore, this method does not have to be called to use a service. This
* method can be used to control when the connection is established.
*
* @param service The name of the service. Valid services are:
*
* - {@link #FILE FILE} - IFS file classes.
*
- {@link #PRINT PRINT} - print classes.
*
- {@link #COMMAND COMMAND} - command and program call classes.
*
- {@link #DATAQUEUE DATAQUEUE} - data queue classes.
*
- {@link #DATABASE DATABASE} - JDBC classes.
*
- {@link #RECORDACCESS RECORDACCESS} - record level access classes.
*
- {@link #CENTRAL CENTRAL} - license management classes.
*
- {@link #SIGNON SIGNON} - sign-on classes.
*
* @param overridePort If non-negative, used to override the port to be used for the connection.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception ExtendedIllegalArgumentException If service is not valid.
* @exception IOException If an error occurs while communicating with the system.
**/
public void connectService(int service, int overridePort) throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Connecting service:", service);
// Validate parameter. HOSTCNN connection is for internal use, do not allow explicit connect requests.
if (service < 0 || service > 7)
throw new ExtendedIllegalArgumentException("service (" + service + ")", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID);
chooseImpl();
// Before the thread to connect server, block the thread to refresh profile token credential.
if (credVault_ instanceof ProfileTokenVault)
{
if (Trace.traceOn_) Trace.log(Trace.INFORMATION, "Before service connected, block the thread of refreshing profile token credential");
((ProfileTokenVault) credVault_).preventRefresh();
}
try {
signon(service == AS400.SIGNON);
impl_.connect(service, overridePort, skipSignonServer_);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Service connected:", AS400.getServerName(service));
}
finally {
// After the thread to connect server, notify the thread to refresh profile token credential.
if (credVault_ instanceof ProfileTokenVault)
{
if (Trace.traceOn_) Trace.log(Trace.INFORMATION, "After service connected, notify the thread of refreshing profile token credential");
((ProfileTokenVault) credVault_).allowRefresh();
}
}
}
// Common code for all the constuctors and readObject.
private void construct()
{
// See if we are running on IBM i.
if (AS400.onAS400)
{
// OK, we are running on IBM i.
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Running on IBM i.");
// Running on IBM i, don't prompt.
guiAvailable_ = false;
}
if (isSecure())
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing secure AS400 object.");
useSSLConnection_ = new SSLOptions();
// Check for proxy encryption mode system property, if not set or not valid retain default of 3.
String prop = SystemProperties.getProperty(SystemProperties.SECUREAS400_PROXY_ENCRYPTION_MODE);
if (prop != null && (prop.equals("1") || prop.equals("2")))
useSSLConnection_.proxyEncryptionMode_ = Integer.parseInt(prop);
}
}
/**
* Disconnects all services. All socket connections associated with this object will be closed. The signon
* information is not changed, and connection properties remain frozen.
*
* @see #resetAllServices
**/
public void disconnectAllServices()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Disconnecting all services...");
if (impl_ != null)
{
impl_.disconnect(AS400.FILE);
impl_.disconnect(AS400.PRINT);
impl_.disconnect(AS400.COMMAND);
impl_.disconnect(AS400.DATAQUEUE);
impl_.disconnect(AS400.DATABASE);
impl_.disconnect(AS400.RECORDACCESS);
impl_.disconnect(AS400.CENTRAL);
impl_.disconnect(AS400.SIGNON);
// Note that HOSTCNN is never disconnected here unless explicitly disconnected.
}
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "All services disconnected.");
}
/**
* Disconnects the service. All socket connections associated with this service and this object will be closed.
*
* @param service The name of the service. Valid services are:
*
* - {@link #FILE FILE} - IFS file classes.
*
- {@link #PRINT PRINT} - print classes.
*
- {@link #COMMAND COMMAND} - command and program call classes.
*
- {@link #DATAQUEUE DATAQUEUE} - data queue classes.
*
- {@link #DATABASE DATABASE} - JDBC classes.
*
- {@link #RECORDACCESS RECORDACCESS} - record level access classes.
*
- {@link #CENTRAL CENTRAL} - license management classes.
*
- {@link #SIGNON SIGNON} - sign-on classes.
*
- {@link #HOSTCNN HOSTCNN} - host-connection classes.
*
* @exception ExtendedIllegalArgumentException If service is not valid.
**/
public void disconnectService(int service)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Disconnecting service:", service);
// Validate parameter. Will allow users to disconnect HOSTCNN.
if (service < 0 || service > 8)
throw new ExtendedIllegalArgumentException("service (" + service + ")", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID);
if (impl_ == null) return;
impl_.disconnect(service);
}
// Fire connect events here so source is public object.
private void fireConnectEvent(ConnectionEvent event, boolean connect)
{
// If we have made it this far, we know we have listeners.
event.setSource(this);
Vector targets = (Vector)connectionListeners_.clone();
for (int i = 0; i < targets.size(); ++i)
{
ConnectionListener target = (ConnectionListener)targets.elementAt(i);
if (connect)
target.connected(event);
else
target.disconnected(event);
}
}
/**
* Generates a profile token on behalf of the provided user identity. This user identity must be associated with a
* user profile via EIM.
*
* Invoking this method does not change the user ID and password assigned to the system or otherwise modify the user
* or authorities under which the application is running. The profile associated with this system object must have
* enough authority to generate an authentication token for another user.
*
* This function is only supported on i5/OS V5R3M0 or greater.
*
* @param userIdentity The LDAP distinguished name.
* @param tokenType The type of profile token to create. Possible types are defined as fields on the
* ProfileTokenCredential class:
*
* - {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_SINGLE_USE
* TYPE_SINGLE_USE}
*
- {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_MULTIPLE_USE_NON_RENEWABLE
* TYPE_MULTIPLE_USE_NON_RENEWABLE}
*
- {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_MULTIPLE_USE_RENEWABLE
* TYPE_MULTIPLE_USE_RENEWABLE}
*
* @param timeoutInterval The number of seconds to expiration when the token is created (1-3600).
* @return A ProfileTokenCredential representing the provided user identity.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
**/
public ProfileTokenCredential generateProfileToken(String userIdentity, int tokenType, int timeoutInterval) throws AS400SecurityException, IOException {
return generateProfileToken(userIdentity, tokenType, timeoutInterval, null, null);
}
/**
* Generates a profile token on behalf of the provided user identity. This user identity must be associated with a
* user profile via EIM.
*
* Invoking this method does not change the user ID and password assigned to the system or otherwise modify the user
* or authorities under which the application is running. The profile associated with this system object must have
* enough authority to generate an authentication token for another user.
*
* This function is only supported on i5/OS V5R3M0 or greater.
*
* @param userIdentity The LDAP distinguished name.
* @param tokenType The type of profile token to create. Possible types are defined as fields on the
* ProfileTokenCredential class:
*
* - {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_SINGLE_USE
* TYPE_SINGLE_USE}
*
- {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_MULTIPLE_USE_NON_RENEWABLE
* TYPE_MULTIPLE_USE_NON_RENEWABLE}
*
- {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_MULTIPLE_USE_RENEWABLE
* TYPE_MULTIPLE_USE_RENEWABLE}
*
* @param timeoutInterval The number of seconds to expiration when the token is created (1-3600).
* @param verificationID The verification ID that will be associated with profile token. The verification ID
* is the label that identifies the specific application, service, or action associated
* with the profile token request. A null value will result in the usage of the
* default value of QIBM_OS400_JT400.
* @param remoteIPAddress The remote IP address (the IP address of the requester) that will be associated with
* profile token. A null value will result in the usage of the local IP address returned
* on the connection to the host server, assuming that the profile token is being created
* by the host server. If the profile token is being created by an ILE API, the remoteIPAddress
* will be null.
*
* @return A ProfileTokenCredential representing the provided user identity.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
**/
public ProfileTokenCredential generateProfileToken(String userIdentity, int tokenType, int timeoutInterval, String verificationID, String remoteIPAddress) throws AS400SecurityException, IOException
{
connectService(AS400.SIGNON);
if (userIdentity == null)
throw new NullPointerException("userIdentity");
ProfileTokenCredential profileToken = new ProfileTokenCredential();
try
{
profileToken.setSystem(this);
profileToken.setTokenType(tokenType);
profileToken.setTimeoutInterval(timeoutInterval);
profileToken.setVerificationID(verificationID);
profileToken.setRemoteIPAddress(remoteIPAddress);
}
catch (PropertyVetoException e)
{
Trace.log(Trace.ERROR, "Unexpected PropertyVetoException:", e);
throw new InternalErrorException(InternalErrorException.UNEXPECTED_EXCEPTION, e);
}
chooseImpl();
synchronized (this) {
impl_.generateProfileToken(profileToken, userIdentity);
}
return profileToken;
}
/**
* Generates a VRM from a version, release, and modification. This can then be used to compare against the VRM
* returned by getVRM().
*
* @param version The version.
* @param release The release.
* @param modification The modification level.
* @return The generated VRM.
* @exception ExtendedIllegalArgumentException If version, release, or modification is not valid.
**/
public static int generateVRM(int version, int release, int modification)
{
// Check for valid input.
if (version < 0 || version > 0xFFFF)
throw new ExtendedIllegalArgumentException("version (" + version + ")", ExtendedIllegalArgumentException.RANGE_NOT_VALID);
if (release < 0 || release > 0xFF)
throw new ExtendedIllegalArgumentException("release (" + release + ")", ExtendedIllegalArgumentException.RANGE_NOT_VALID);
if (modification < 0 || modification > 0xFF)
throw new ExtendedIllegalArgumentException("modification (" + modification + ")", ExtendedIllegalArgumentException.RANGE_NOT_VALID);
return (version << 16) + (release << 8) + modification;
}
/**
* Returns the authentication scheme for this object. By default this object starts in password mode. This value may
* not be correct before a connection to the system has been made. Valid authentication schemes are:
*
* - {@link #AUTHENTICATION_SCHEME_PASSWORD AUTHENTICATION_SCHEME_PASSWORD} - passwords are used.
*
- {@link #AUTHENTICATION_SCHEME_GSS_TOKEN AUTHENTICATION_SCHEME_GSS_TOKEN} - GSS tokens are used.
*
- {@link #AUTHENTICATION_SCHEME_PROFILE_TOKEN AUTHENTICATION_SCHEME_PROFILE_TOKEN} - profile tokens are used.
*
- {@link #AUTHENTICATION_SCHEME_IDENTITY_TOKEN AUTHENTICATION_SCHEME_IDENTITY_TOKEN} - identity tokens are
* used.
*
*
* @return The authentication scheme in use for this object.
**/
public int getAuthenticationScheme()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting authentication scheme, scheme:", credVault_.getType());
return credVault_.getType();
}
/**
* Returns the CCSID for this object. The CCSID returned either is the one retrieved based on the user profile or is
* set by the setCcsid() method.
*
* @return The CCSID in use for this object.
**/
public int getCcsid()
{
if (ccsid_ == 0)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting CCSID.");
try
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Retrieving CCSID from system...");
chooseImpl();
signon(false);
ccsid_ = signonInfo_.serverCCSID;
}
catch (Exception e)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Taking best guess CCSID:", e);
ccsid_ = ExecutionEnvironment.getBestGuessAS400Ccsid();
}
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "CCSID:", ccsid_);
}
return ccsid_;
}
// Calculate number of days until user's password expires.
private int getDaysToExpiration()
{
if (signonInfo_ != null)
{
GregorianCalendar expirationDate = signonInfo_.expirationDate;
GregorianCalendar now = signonInfo_.currentSignonDate;
if (expirationDate != null && now != null)
{
long lExpiration = expirationDate.getTimeInMillis();
long lNow = now.getTimeInMillis();
// Divide by number of seconds in day, round up.
int days = (int) (((lExpiration - lNow) / 0x5265C00) + 1);
return days;
}
}
// No expiration date.
return 365;
}
/**
* Returns the default sign-on handler. If none has been specified, returns an instance of the Toolbox's internal
* sign-on handler.
*
* @return The default sign-on handler. Never returns null.
* @see #setDefaultSignonHandler
**/
public static SignonHandler getDefaultSignonHandler()
{
if (defaultSignonHandler_ != null) return defaultSignonHandler_;
try {
return (SignonHandler)defaultSignonHandlerClass_.newInstance();
}
catch (Exception e)
{
Trace.log(Trace.ERROR, "Unable to cast specified default sign-on handler to a SignonHandler: " + defaultSignonHandlerClass_.getName(), e);
return new ToolboxSignonHandler();
}
}
/**
* Returns the relational database name (RDB name) used for record-level access (DDM) connections. The RDB name
* corresponds to the independent auxiliary storage pool (IASP) that is being used.
*
* @return The name of the IASP or RDB that is in use by this object's RECORDACCESS service, or null if the IASP
* used will be the default system pool (*SYSBAS).
* @see #setDDMRDB
**/
public String getDDMRDB()
{
return ddmRDB_;
}
/**
* Returns the default user ID for this system name. This user ID is used to connect if a user ID was not used to
* construct the object.
*
* @param systemName The name of the IBM i system.
* @return The default user ID for this system. A null is returned if there is not a default user.
**/
public static String getDefaultUser(String systemName)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting the default user, system name:", systemName);
if (systemName == null)
throw new NullPointerException("systemName");
String defaultUser = (String)AS400.defaultUsers.get(resolveSystem(systemName));
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Default user:", defaultUser);
return defaultUser;
}
/**
* Returns the GSS name string. This method will only return the information provided on the setGSSName() method.
*
* @return The GSS name string, or an empty string ("") if not set.
**/
public synchronized String getGSSName()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting GSS name:", gssName_);
return gssName_;
}
/**
* Returns the option for how the JGSS framework will be used.
*
* @return A constant indicating how the JGSS framework will be used. Valid values are:
*
* - {@link #GSS_OPTION_MANDATORY GSS_OPTION_MANDATORY}
*
- {@link #GSS_OPTION_FALLBACK GSS_OPTION_FALLBACK}
*
- {@link #GSS_OPTION_NONE GSS_OPTION_NONE}
*
**/
public int getGSSOption()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting GSS option:", gssOption_);
return gssOption_;
}
/**
* Get underlying AS400Impl object. Should only be used by code internal to the driver.
*
* @return underlying AS400Impl object
*/
public AS400Impl getImpl()
{
chooseImpl();
return impl_;
}
// Returns the job CCSID.
int getJobCcsid() throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting job CCSID.");
chooseImpl();
signon(false);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Job CCSID:", signonInfo_.serverCCSID);
return signonInfo_.serverCCSID;
}
/**
* Returns the encoding that corresponds to the job CCSID.
*
* @return The encoding.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
* @exception InterruptedException If this thread is interrupted.
**/
public String getJobCCSIDEncoding() throws AS400SecurityException, IOException, InterruptedException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting job CCSID encoding.");
if (signonInfo_ == null) {
chooseImpl();
signon(false);
}
int ccsid = signonInfo_.serverCCSID;
String encoding = impl_.ccsidToEncoding(ccsid);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Job CCSID encoding:", encoding);
return encoding;
}
/**
* Returns an array of Job objects representing the jobs to which this object is connected. This information is only
* available when connecting to i5/OS V5R2M0 and later systems. The array will be of length zero if no connections
* are currently active.
*
* @param service The name of the service. Valid services are:
*
* - {@link #FILE FILE} - IFS file classes.
*
- {@link #PRINT PRINT} - print classes.
*
- {@link #COMMAND COMMAND} - command and program call classes.
*
- {@link #DATAQUEUE DATAQUEUE} - data queue classes.
*
- {@link #DATABASE DATABASE} - JDBC classes.
*
- {@link #RECORDACCESS RECORDACCESS} - record level access classes.
*
- {@link #CENTRAL CENTRAL} - license management classes.
*
- {@link #SIGNON SIGNON} - sign-on classes.
*
- {@link #HOSTCNN HOSTCNN} - host-connection classes.
*
* @return The array of job objects.
* @exception ExtendedIllegalArgumentException If service is not valid.
**/
public Job[] getJobs(int service)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting jobs, service:", service);
// Validate parameter.
if (service < 0 || service > 8)
{
Trace.log(Trace.ERROR, "Value of parameter 'service' is not valid:", service);
throw new ExtendedIllegalArgumentException("service (" + service + ")", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID);
}
if (impl_ == null) return new Job[0];
String[] jobStrings = impl_.getJobs(service);
Job[] jobs = new Job[jobStrings.length];
for (int i = 0; i < jobStrings.length; ++i)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing Job for job:", jobStrings[i]);
if (jobStrings[i] == null || jobStrings[i].length() == 0) return new Job[0];
StringTokenizer tokenizer = new StringTokenizer(jobStrings[i], "/");
String jobNumber = tokenizer.nextToken();
String jobUser = tokenizer.nextToken();
String jobName = tokenizer.nextToken();
jobs[i] = new Job(this, jobName, jobUser, jobNumber);
}
return jobs;
}
/**
* Returns the Locale associated with this system object. The Locale may have been set with the setLocale() method,
* or it may be the default Locale for the client environment. Unless specifically overridden, this Locale is used
* to set the National Language Version (NLV) on the system. Only the COMMAND, PRINT, and DATABASE services accept
* an NLV.
*
* @return The Locale object.
**/
public Locale getLocale()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting locale: " + locale_);
return locale_;
}
/**
* Returns the modification level of the IBM i system.
*
* A connection is required to the system to retrieve this information. If a connection has not been established,
* one is created to retrieve the information.
*
* @return The modification level. For example, version 5, release 1, modification level 0 returns 0.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
**/
public int getModification() throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting modification level.");
if (signonInfo_ == null) {
chooseImpl();
signon(false);
}
int modification = signonInfo_.version.getModificationLevel();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Modification level:", modification);
return modification;
}
/**
* Returns the National Language Version (NLV) that will be sent to the system. Only the COMMAND, PRINT, and
* DATABASE services accept an NLV.
*
* @return The NLV.
**/
public String getNLV()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting NLV:", nlv_);
return nlv_;
}
/**
* Returns the password expiration date for the signed-on user. If the profile's password expiration interval is set
* to *NOMAX, null is returned.
*
* A connection is required to retrieve this information. If a connection has not been established, one is created
* to retrieve the information.
*
* @return The password expiration date. If the profile has no password expiration data (*NOMAX), null is returned.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
**/
public GregorianCalendar getPasswordExpirationDate() throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting password expiration date.");
if (signonInfo_ == null) {
chooseImpl();
signon(false);
}
GregorianCalendar expire = signonInfo_.expirationDate;
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Password expiration date: " + expire);
return (expire == null) ? null : (GregorianCalendar)expire.clone();
}
/**
* Set a flag to indicate whether or not to use the password expiration warning days from the QPWDEXPWRN system
* value. This capability is supported with V6R1M0 and later systems with V6R1M0 5761SS1 PTF SI48808 or V7R1M0
* 5770SS1 PTF SI48809.
*
* @param useSystem indicates whether or not to use password expiration warning days from the QPWDEXPWRN system
* value
*/
public void setUseSystemPasswordExpirationWarningDays(boolean useSystem)
{
if (useSystem) {
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Use system password expiration(QPWDEXPWRN) warning.");
useSystemExpirationWarning_ = true;
} else {
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Don't use system password expiration(QPWDEXPWRN) warning.");
useSystemExpirationWarning_ = false;
}
}
/**
* Returns the number of days before password expiration to start warning the user based on the value of the
* QPWDEXPWRN system value. This capability is supported with V6R1M0 and later systems with V6R1M0 5761SS1 PTF
* SI48808 or V7R1M0 5770SS1 PTF SI48809.
*
* @return The number of days before password expiration to start warning the user. If
* {@link #setUseSystemPasswordExpirationWarningDays} is enabled and supported, return the value of the
* QPWDEXPWRN system value. Otherwise, return {@link #getPasswordExpirationWarningDays}.
* @throws AS400SecurityException If a security or authority error occurs.
* @throws IOException If an error occurs while communicating with the system.
*/
public int getSystemPasswordExpirationWarningDays()throws AS400SecurityException, IOException
{
if (useSystemExpirationWarning_)
{
if (signonInfo_ == null) {
chooseImpl();
signon(false);
}
if (signonInfo_.PWDexpirationWarning > 0) {
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Use system password expiration(QPWDEXPWRN) warning: " + signonInfo_.PWDexpirationWarning);
return signonInfo_.PWDexpirationWarning;
}
}
return getPasswordExpirationWarningDays();
}
/**
* Determines if the password expiration date for the user profile is within the password expiration warning days
* for the system returned by {@link #getPasswordExpirationDays()}.
*
* @return true if the password expiration date for the user profile is within the password expiration days;
* otherwise, return false
* @throws AS400SecurityException If a security or authority error occurs.
* @throws IOException If an error occurs while communicating with the system.
*/
public boolean isInPasswordExpirationWarningDays() throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Checking if within the password expiration warning days for the system. " );
chooseImpl();
signon(false);
boolean warn = getDaysToExpiration() <= getSystemPasswordExpirationWarningDays();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "In password expiration warning days: " + warn);
return warn;
}
/**
* Returns the number of days until the user profile's password expires.
*
* A connection is required to retrieve this information. If a connection has not been established, one is created
* to retrieve the information.
*
* @return The number of days until the user profiles' password expires.
* @throws AS400SecurityException If a security or authority error occurs.
* @throws IOException If an error occurs while communicating with the system.
*/
public int getPasswordExpirationDays() throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting password expiration warning days.");
chooseImpl();
signon(false);
int days = getDaysToExpiration();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Password expiration days: " + days);
return days;
}
/**
* Returns the number of days before password expiration to start warning the user.
*
* @return The number of days before expiration to warn the user.
**/
public static int getPasswordExpirationWarningDays()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting the password expiration warning days:", AS400.expirationWarning);
return AS400.expirationWarning;
}
/**
* Returns the date of the last successful sign-on.
*
* A connection is required to retrieve this information. If a connection has not been established, one is created
* to retrieve the information.
*
* @return The date of the last successful sign-on.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
**/
public GregorianCalendar getPreviousSignonDate() throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting previous signon date.");
if (signonInfo_ == null) {
chooseImpl();
signon(false);
}
GregorianCalendar last = signonInfo_.lastSignonDate;
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Previous signon date: " + last);
return (last == null) ? null : (GregorianCalendar)last.clone();
}
/**
* Returns a profile token representing the signed-on user profile.
*
* The returned token will be created single-use with a one hour time to expiration. Subsequent method calls will
* return the same token, regardless of the token status.
*
* This function is not supported if the assigned password is *CURRENT.
*
* This function is only supported if the system is at i5/OS V4R5M0 or greater.
*
* Note: If an additional authentication factor has been set for the AS400 object, it will be used when
* generating the profile token.
*
* @return A ProfileTokenCredential representing the currently signed on user.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
* @exception InterruptedException If this thread is interrupted.
* @deprecated Use {@link #getProfileToken(int,int) getProfileToken(int,int)} instead.
**/
@Deprecated
public ProfileTokenCredential getProfileToken() throws AS400SecurityException, IOException, InterruptedException
{
connectService(AS400.SIGNON);
if (signonInfo_.profileToken == null)
signonInfo_.profileToken = getProfileToken(ProfileTokenCredential.TYPE_SINGLE_USE, 3600);
return (ProfileTokenCredential)signonInfo_.profileToken;
}
/**
* Authenticates the assigned user profile and password and returns a corresponding ProfileTokenCredential if
* successful.
*
* This function is not supported if the assigned password is *CURRENT and cannot be used to generate a renewable
* token. This function is only supported if the system is at i5/OS V4R5M0 or greater.
*
* Note: If an additional authentication factor has been set for the AS400 object, it will be used when
* generating the profile token.
*
* @param tokenType The type of profile token to create. Possible types are defined as fields on the
* ProfileTokenCredential class:
*
* - {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_SINGLE_USE
* TYPE_SINGLE_USE}
*
- {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_MULTIPLE_USE_NON_RENEWABLE
* TYPE_MULTIPLE_USE_NON_RENEWABLE}
*
* @param timeoutInterval The number of seconds to expiration when the token is created (1-3600).
* @return A ProfileTokenCredential representing the signed-on user.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
* @exception InterruptedException If this thread is interrupted.
**/
public ProfileTokenCredential getProfileToken(int tokenType, int timeoutInterval) throws AS400SecurityException, IOException, InterruptedException {
return getProfileToken(tokenType, timeoutInterval, null, null);
}
/**
* Authenticates the assigned user profile and password and returns a corresponding ProfileTokenCredential if
* successful.
*
* This function is not supported if the assigned password is *CURRENT and cannot be used to generate a renewable
* token. This function is only supported if the system is at i5/OS V4R5M0 or greater.
*
* Note: If an additional authentication factor has been set for the AS400 object, it will be used when
* generating the profile token.
*
* @param tokenType The type of profile token to create. Possible types are defined as fields on the
* ProfileTokenCredential class:
*
* - {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_SINGLE_USE
* TYPE_SINGLE_USE}
*
- {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_MULTIPLE_USE_NON_RENEWABLE
* TYPE_MULTIPLE_USE_NON_RENEWABLE}
*
* @param timeoutInterval The number of seconds to expiration when the token is created (1-3600).
* @param verificationID The verification ID that will be associated with profile token. The verification ID
* is the label that identifies the specific application, service, or action associated
* with the profile token request. A null value will result in the usage of the
* default value of QIBM_OS400_JT400.
* @param remoteIPAddress The remote IP address (the IP address of the requester) that will be associated with
* profile token. A null value will result in the usage of the local IP address returned
* on the connection to the host server, assuming that the profile token is being created
* by the host server. If the profile token is being created by an ILE API, the remoteIPAddress
* will be null.
* @return A ProfileTokenCredential representing the signed-on user.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
* @exception InterruptedException If this thread is interrupted.
**/
public ProfileTokenCredential getProfileToken(int tokenType, int timeoutInterval, String verificationID, String remoteIPAddress) throws AS400SecurityException, IOException, InterruptedException
{
connectService(AS400.SIGNON);
// If the password is not set and we are not using Kerberos.
if (credVault_.isEmpty() && credVault_.getType() != AUTHENTICATION_SCHEME_GSS_TOKEN)
throw new AS400SecurityException(AS400SecurityException.PASSWORD_NOT_SET);
if (tokenType == ProfileTokenCredential.TYPE_MULTIPLE_USE_RENEWABLE)
{
Trace.log(Trace.ERROR, "Request not supported for renewable token type.");
throw new AS400SecurityException(AS400SecurityException.REQUEST_NOT_SUPPORTED);
}
ProfileTokenCredential profileToken = new ProfileTokenCredential();
try
{
profileToken.setSystem(this);
profileToken.setTokenType(tokenType);
profileToken.setTimeoutInterval(timeoutInterval);
profileToken.setVerificationID(verificationID);
profileToken.setRemoteIPAddress(remoteIPAddress);
}
catch (PropertyVetoException e)
{
Trace.log(Trace.ERROR, "Unexpected PropertyVetoException:", e);
throw new InternalErrorException(InternalErrorException.UNEXPECTED_EXCEPTION, e);
}
byte[] proxySeed = new byte[9];
CredentialVault.rng.nextBytes(proxySeed);
synchronized (this)
{
// The 'impl' needs our credential to authenticate with the system
// (i.e. to make sure we have enough authority to generate the profile token).
// Note that we do not send across the bytes in the clear, but encode them
// using random seeds generated and exchanged with the 'impl' object.
// Also, Don't re-encode our own vault; we might need to reuse it later.
CredentialVault tempVault = (CredentialVault)credVault_.clone();
tempVault.storeEncodedUsingExternalSeeds(proxySeed, impl_.exchangeSeed(proxySeed));
impl_.generateProfileToken(profileToken, userId_, tempVault, additionalAuthenticationFactor_, gssName_);
}
return profileToken;
}
/**
* Authenticates the given user profile and password and returns a corresponding ProfileTokenCredential if
* successful.
*
* Invoking this method does not change the user ID and password assigned to the system or otherwise modify the user
* or authorities under which the application is running.
*
* This method generates a single use token with a timeout of one hour.
*
* This function is only supported if the system is at i5/OS V4R5M0 or greater.
*
* Note: Providing an incorrect password increments the number of failed sign-on attempts for the user
* profile, and can result in the profile being disabled. Refer to documentation on the
* ProfileTokenCredential class for additional restrictions.
*
* @param userId The user profile name.
* @param password The user profile password.
* @return A ProfileTokenCredential representing the authenticated profile and password.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
* @exception InterruptedException If this thread is interrupted.
* @deprecated Use {@link #getProfileToken(String, char[]) getProfileToken(String, char[])} instead.
**/
@Deprecated
public ProfileTokenCredential getProfileToken(String userId, String password) throws AS400SecurityException, IOException, InterruptedException {
return getProfileToken(userId, password, ProfileTokenCredential.TYPE_SINGLE_USE, 3600);
}
/**
* Authenticates the given user profile and password and returns a corresponding ProfileTokenCredential if
* successful.
*
* Invoking this method does not change the user ID and password assigned to the system or otherwise modify the user
* or authorities under which the application is running.
*
* This method generates a single use token with a timeout of one hour.
*
* This function is only supported if the system is at i5/OS V4R5M0 or greater.
*
* Note: Providing an incorrect password increments the number of failed sign-on attempts for the user
* profile, and can result in the profile being disabled. Refer to documentation on the
* ProfileTokenCredential class for additional restrictions.
*
* @param userId The user profile name.
* @param password The user profile password.
* @return A ProfileTokenCredential representing the authenticated profile and password.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
* @exception InterruptedException If this thread is interrupted.
**/
public ProfileTokenCredential getProfileToken(String userId, char[] password) throws AS400SecurityException, IOException, InterruptedException {
return getProfileToken(userId, password, ProfileTokenCredential.TYPE_SINGLE_USE, 3600);
}
/**
* Authenticates the given user profile and password and returns a corresponding ProfileTokenCredential if
* successful.
*
* Invoking this method does not change the user ID and password assigned to the system or otherwise modify the user
* or authorities under which the application is running.
*
* This function is only supported if the system is at i5/OS V4R5M0 or greater.
*
* Note: Providing an incorrect password increments the number of failed sign-on attempts for the user
* profile, and can result in the profile being disabled. Refer to documentation on the
* ProfileTokenCredential class for additional restrictions.
*
* @param userId The user profile name.
* @param password The user profile password.
* @param tokenType The type of profile token to create. Possible types are defined as fields on the
* ProfileTokenCredential class:
*
* - {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_SINGLE_USE
* TYPE_SINGLE_USE}
*
- {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_MULTIPLE_USE_NON_RENEWABLE
* TYPE_MULTIPLE_USE_NON_RENEWABLE}
*
- {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_MULTIPLE_USE_RENEWABLE
* TYPE_MULTIPLE_USE_RENEWABLE}
*
* @param timeoutInterval The number of seconds to expiration when the token is created (1-3600).
* @return A ProfileTokenCredential representing the authenticated profile and password.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
* @exception InterruptedException If this thread is interrupted.
* @deprecated Use {@link #getProfileToken(String, char[],int,int) getProfileToken(String, char[],int,int)} instead.
**/
@Deprecated
public ProfileTokenCredential getProfileToken(String userId, String password, int tokenType, int timeoutInterval) throws AS400SecurityException, IOException, InterruptedException
{
char[] passwordChars = (password == null) ? null : password.toCharArray();
try
{
ProfileTokenCredential pt = getProfileToken(userId, passwordChars, tokenType, timeoutInterval);
return pt;
}
finally {
PasswordVault.clearArray(passwordChars);
}
}
/**
* Authenticates the given user profile and password and returns a corresponding ProfileTokenCredential if
* successful.
*
* Invoking this method does not change the user ID and password assigned to the system or otherwise modify the user
* or authorities under which the application is running.
*
* This function is only supported if the system is at i5/OS V4R5M0 or greater.
*
* Note: Providing an incorrect password increments the number of failed sign-on attempts for the user
* profile, and can result in the profile being disabled. Refer to documentation on the
* ProfileTokenCredential class for additional restrictions.
*
* @param userId The user profile name.
* @param password The user profile password.
* @param tokenType The type of profile token to create. Possible types are defined as fields on the
* ProfileTokenCredential class:
*
* - {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_SINGLE_USE
* TYPE_SINGLE_USE}
*
- {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_MULTIPLE_USE_NON_RENEWABLE
* TYPE_MULTIPLE_USE_NON_RENEWABLE}
*
- {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_MULTIPLE_USE_RENEWABLE
* TYPE_MULTIPLE_USE_RENEWABLE}
*
* @param timeoutInterval The number of seconds to expiration when the token is created (1-3600).
* @return A ProfileTokenCredential representing the authenticated profile and password.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
* @exception InterruptedException If this thread is interrupted.
**/
public ProfileTokenCredential getProfileToken(String userId, char[] password, int tokenType, int timeoutInterval) throws AS400SecurityException, IOException, InterruptedException
{
return getProfileToken(userId, password, null, tokenType, timeoutInterval, null);
}
/**
* Authenticates the given user profile and password and returns a corresponding ProfileTokenCredential if
* successful.
*
* Invoking this method does not change the user ID and password assigned to the system or otherwise modify the user
* or authorities under which the application is running.
*
* This function is only supported if the system is at i5/OS V4R5M0 or greater.
*
* Note: Providing an incorrect password increments the number of failed sign-on attempts for the user
* profile, and can result in the profile being disabled. Refer to documentation on the
* ProfileTokenCredential class for additional restrictions.
*
* @param userId The user profile name.
* @param password The user profile password.
* @param additionalAuthFactor The additional authentication factor or null if not specifying one.
* @param tokenType The type of profile token to create. Possible types are defined as fields on the
* ProfileTokenCredential class:
*
* - {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_SINGLE_USE
* TYPE_SINGLE_USE}
*
- {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_MULTIPLE_USE_NON_RENEWABLE
* TYPE_MULTIPLE_USE_NON_RENEWABLE}
*
- {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_MULTIPLE_USE_RENEWABLE
* TYPE_MULTIPLE_USE_RENEWABLE}
*
* @param timeoutInterval The number of seconds to expiration when the token is created (1-3600).
* @param verificationID The verification ID that will be associated with profile token. The verification ID
* is the label that identifies the specific application, service, or action associated
* with the profile token request. A null value will result in the usage of the
* default value of QIBM_OS400_JT400.
* @param remoteIPAddress The remote IP address (the IP address of the requester) that will be associated with
* profile token. AA null value will result in the usage of the local IP address returned
* on the connection to the host server, assuming that the profile token is being created
* by the host server. If the profile token is being created by an ILE API, the remoteIPAddress
* will be null.
* @return A ProfileTokenCredential representing the authenticated profile and password.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception ExtendedIllegalArgumentException If userId length is not valid.
* @exception IOException If an error occurs while communicating with the system.
* @exception InterruptedException If this thread is interrupted.
**/
public ProfileTokenCredential getProfileToken(String userId, char[] password, char[] additionalAuthFactor, int tokenType, int timeoutInterval,
String verificationID, String remoteIPAddress) throws AS400SecurityException, IOException, InterruptedException
{
ProfileTokenEnhancedInfo enhancedInfo = new ProfileTokenEnhancedInfo();
enhancedInfo.setVerificationID(verificationID);
enhancedInfo.setRemoteIPAddress(remoteIPAddress);
return getProfileToken(userId,password,additionalAuthFactor,tokenType, timeoutInterval, enhancedInfo);
}
/**
* Authenticates the given user profile and password and returns a corresponding ProfileTokenCredential if
* successful.
*
* Invoking this method does not change the user ID and password assigned to the system or otherwise modify the user
* or authorities under which the application is running.
*
* This function is only supported if the system is at i5/OS V4R5M0 or greater.
*
* Note: Providing an incorrect password increments the number of failed sign-on attempts for the user
* profile, and can result in the profile being disabled. Refer to documentation on the
* ProfileTokenCredential class for additional restrictions.
*
* @param userId The user profile name.
* @param password The user profile password.
* @param additionalAuthFactor The additional authentication factor or null if not specifying one.
* @param tokenType The type of profile token to create. Possible types are defined as fields on the
* ProfileTokenCredential class:
*
* - {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_SINGLE_USE
* TYPE_SINGLE_USE}
*
- {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_MULTIPLE_USE_NON_RENEWABLE
* TYPE_MULTIPLE_USE_NON_RENEWABLE}
*
- {@link com.ibm.as400.security.auth.ProfileTokenCredential#TYPE_MULTIPLE_USE_RENEWABLE
* TYPE_MULTIPLE_USE_RENEWABLE}
*
* @param timeoutInterval The number of seconds to expiration when the token is created (1-3600).
* @param enhancedInfo Information used for creating an enhanced profile token.
* @return A ProfileTokenCredential representing the authenticated profile and password.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception ExtendedIllegalArgumentException If userId length is not valid.
* @exception IOException If an error occurs while communicating with the system.
* @exception InterruptedException If this thread is interrupted.
**/
public ProfileTokenCredential getProfileToken(String userId, char[] password, char[] additionalAuthFactor, int tokenType, int timeoutInterval,
ProfileTokenEnhancedInfo enhancedInfo ) throws AS400SecurityException, IOException, InterruptedException
{
connectService(AS400.SIGNON);
if (userId == null)
throw new NullPointerException("userId");
if (userId.length() > 10)
throw new ExtendedIllegalArgumentException("userId", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
if (enhancedInfo == null) {
enhancedInfo = new ProfileTokenEnhancedInfo();
}
checkPasswordNullAndLength(password, "password");
if (isTurkish()) {
userId = userId.toUpperCase(Locale.ENGLISH);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "This system locale is Turkish, userId.toUpperCase(Locale.ENGLISH)");
}
userId = resolveUserId(userId.toUpperCase());
ProfileTokenCredential profileToken = new ProfileTokenCredential();
try
{
profileToken.setSystem(this);
profileToken.setTokenType(tokenType);
profileToken.setTimeoutInterval(timeoutInterval);
profileToken.setEnhancedInfo(enhancedInfo);
}
catch (PropertyVetoException e)
{
Trace.log(Trace.ERROR, "Unexpected PropertyVetoException:", e);
throw new InternalErrorException(InternalErrorException.UNEXPECTED_EXCEPTION, e);
}
byte[] proxySeed = new byte[9];
CredentialVault.rng.nextBytes(proxySeed);
synchronized (this)
{
PasswordVault tempVault = new PasswordVault(password);
tempVault.storeEncodedUsingExternalSeeds(proxySeed, impl_.exchangeSeed(proxySeed));
impl_.generateProfileToken(profileToken, userId, tempVault, additionalAuthFactor, gssName_);
}
return profileToken;
}
/**
* Returns the name of the middle-tier machine where the proxy server is running.
*
* @return The name of the middle-tier machine where the proxy server is running, or an empty string ("") if not
* set.
**/
public String getProxyServer()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting proxy server:", proxyServer_);
return proxyServer_;
}
/**
* Returns the release of the IBM i system.
*
* A connection is required to the system in order to retrieve this information. If a connection has not been
* established, one is created to retrieve the system information.
*
* @return The release of the IBM i system. For example, version 5, release 1, modification level 0, returns 1.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
**/
public int getRelease() throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting release level.");
if (signonInfo_ == null) {
chooseImpl();
signon(false);
}
int release = signonInfo_.version.getRelease();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Release level:", release);
return release;
}
/**
* Converts a service constant to the string representation of the service. For example, the integer AS400.File
* corresponds to the string "as-file".
*
* @param service The service represented by it's integer value.
* @return The string representation of the service.
* @exception ExtendedIllegalArgumentException If service is not valid.
*/
public static String getServerName(int service)
{
switch (service)
{
case AS400.FILE:
return "as-file";
case AS400.PRINT:
return "as-netprt";
case AS400.COMMAND:
return "as-rmtcmd";
case AS400.DATAQUEUE:
return"as-dtaq";
case AS400.DATABASE:
return "as-database";
case AS400.RECORDACCESS:
return "as-ddm";
case AS400.CENTRAL:
return "as-central";
case AS400.HOSTCNN:
return "as-hostcnn";
case AS400.SIGNON:
return "as-signon";
default:
throw new ExtendedIllegalArgumentException("service (" + service + ")", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID);
}
}
/**
* Returns the service port stored in the service port table for the specified service.
*
* @param service The name of the service. Valid services are:
*
* - {@link #FILE FILE} - IFS file classes.
*
- {@link #PRINT PRINT} - print classes.
*
- {@link #COMMAND COMMAND} - command and program call classes.
*
- {@link #DATAQUEUE DATAQUEUE} - data queue classes.
*
- {@link #DATABASE DATABASE} - JDBC classes.
*
- {@link #RECORDACCESS RECORDACCESS} - record level access classes.
*
- {@link #CENTRAL CENTRAL} - license management classes.
*
- {@link #SIGNON SIGNON} - sign-on classes.
*
- {@link #HOSTCNN HOSTCNN} - host-connection classes.
*
* @return The port specified in the service port table. The value {@link #USE_PORT_MAPPER USE_PORT_MAPPER} will be
* returned if the service has not been set, and the service has not been connected.
* @exception ExtendedIllegalArgumentException If service is not valid.
* @exception ExtendedIllegalStateException If system name not set.
**/
public int getServicePort(int service)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting service port, service:", service);
// Validate parameter.
if (service < 0 || service > 8)
{
throw new ExtendedIllegalArgumentException("service (" + service + ")", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID);
}
// Validate state.
if (systemName_.length() == 0 && !systemNameLocal_)
{
Trace.log(Trace.ERROR, "Cannot get service port before system name is set.");
throw new ExtendedIllegalStateException("systemName", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
chooseImpl();
int port = impl_.getServicePort((systemNameLocal_) ? "localhost" : systemName_, service);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Service port:", port);
return port;
}
/**
* Returns the date for the current sign-on.
*
* A connection is required to the system to retrieve this information. If a connection has not been established,
* one is created to retrieve the system information.
*
* @return The date for the current sign-on.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
**/
public GregorianCalendar getSignonDate() throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting signon date.");
chooseImpl();
signon(false);
GregorianCalendar current = signonInfo_.currentSignonDate;
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Signon date: " + current);
return (current == null) ? null : (GregorianCalendar)current.clone();
}
/**
* Returns the sign-on handler that is used by this object. Never returns null.
*
* @return The sign-on handler.
* @see #setSignonHandler
* @see #setDefaultSignonHandler
**/
public SignonHandler getSignonHandler()
{
return (signonHandler_ != null) ? signonHandler_ : getDefaultSignonHandler();
}
/**
* Returns a copy of the socket options object.
*
* @return The socket options object.
**/
public SocketProperties getSocketProperties()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting socket properties.");
SocketProperties socketProperties = new SocketProperties();
socketProperties.copyValues(socketProperties_);
return socketProperties;
}
/**
* Returns the name of the IBM i system. The system name is provided on the constructor or may have been provided by
* the user at the sign-on prompt.
*
* @return The name of the IBM i system, or an empty string ("") if not set.
**/
public String getSystemName()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting system name: " + systemName_ + ", is local:", systemNameLocal_);
return (systemNameLocal_) ? "localhost" : systemName_;
}
/**
* Returns the time zone of the IBM i system. The TimeZone object will have the correct UTC offset for the system.
*
* @return A TimeZone object representing the time zone for the system.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception ErrorCompletingRequestException If an error occurs before the request is completed.
* @exception InterruptedException If this thread is interrupted.
* @exception IOException If an error occurs while communicating with the system.
* @exception ObjectDoesNotExistException If the API used to retrieve the information does not exist on the
* system.
* @see DateTimeConverter#timeZoneForSystem
* @deprecated Use {@link #getTimeZone() getTimeZone()} instead.
**/
@Deprecated
public TimeZone getSystemTimeZone()
throws AS400SecurityException,
ErrorCompletingRequestException,
InterruptedException,
IOException,
ObjectDoesNotExistException
{
return getTimeZone();
}
/**
* Returns the time zone of the IBM i system. The TimeZone object will have the correct UTC offset for the system.
*
* @return A TimeZone object representing the time zone for the system.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception ErrorCompletingRequestException If an error occurs before the request is completed.
* @exception InterruptedException If this thread is interrupted.
* @exception IOException If an error occurs while communicating with the system.
* @exception ObjectDoesNotExistException If the API used to retrieve the information does not exist on the
* system.
* @see DateTimeConverter#timeZoneForSystem
**/
public TimeZone getTimeZone()
throws AS400SecurityException,
ErrorCompletingRequestException,
InterruptedException,
IOException,
ObjectDoesNotExistException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting time zone for System");
if (timezone_ == null)
timezone_ = DateTimeConverter.timeZoneForSystem(this);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Time zone:", timezone_.getDisplayName());
return timezone_;
}
/**
* Returns the timezone of the IBM i, if available. If the timezone is not available, then the default timezone for
* the client will be return.
*
* @param system System to get the timezone from
* @return The timezone of the IBM i if available.
*/
public static TimeZone getDefaultTimeZone(AS400 system)
{
TimeZone timeZone = null;
if (system != null)
{
try {
timeZone = system.getTimeZone();
} catch (Exception e) {
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Exception obtaining timezone ", e);
}
}
if (timeZone == null)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Defaulting to local timezone");
timeZone = TimeZone.getDefault();
}
return timeZone;
}
/**
* Returns the user ID. The user ID returned may be set as a result of the constructor, or it may be what the user
* typed in at the sign-on prompt.
*
* @return The user ID, or an empty string ("") if not set.
**/
public String getUserId()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting user ID:", userId_);
userId_ = resolveUserId(userId_, credVault_.getType(), mustUseSuppliedProfile_);
return userId_;
}
/**
* Returns the user ID. The user ID returned may be set as a result of the constructor, or it may be what the user
* typed in at the sign-on prompt.
*
* @param forceRefresh If true, force the current userID information to be reloaded. When running natively with
* system name specified as localhost
, this will obtain the user profile under
* which the thread is currently running. This may have changed since object construction, if a
* profile swap has been performed on the thread. If false, or if running remotely, then this
* method behaves identically to {@link #getUserId getUserId()}.
* @return The user ID, or an empty string ("") if not set.
**/
public String getUserId(boolean forceRefresh)
{
if (!forceRefresh)
return getUserId();
if (Trace.traceOn_)
Trace.log(Trace.DIAGNOSTIC, "Getting current user ID:", userId_);
String currentUserID = userId_;
if (systemNameLocal_ && AS400.onAS400)
{
try {
currentUserID = CurrentUser.getUserID(AS400.nativeVRM.getVersionReleaseModification());
if (currentUserID == null || currentUserID.length() == 0)
currentUserID = userId_;
}
catch (Throwable t) {
if (Trace.traceOn_)
Trace.log(Trace.DIAGNOSTIC, t);
currentUserID = userId_;
}
}
return currentUserID;
}
/**
* Returns the version of the IBM i system.
*
* A connection is required to the system to retrieve this information. If a connection has not been established,
* one is created to retrieve the system information.
*
* @return The version of the IBM i system. For example, version 5, release 1, modification level 0, returns 5.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
**/
public int getVersion() throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting version level.");
if (signonInfo_ == null) {
chooseImpl();
signon(false);
}
int version = signonInfo_.version.getVersion();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Version level:", version);
return version;
}
/**
* Returns the version, release, and modification level a given system.
*
* @param systemName The IP address or hostname of the target system.
* @param useSSL Whether or not secure connections should be used when communicating with the host servers.
*
* @return The high 16-bit is the version, the next 8 bits is the release, and the low 8 bits is the modification
* level. Thus version 5, release 1, modification level 0, returns 0x00050100.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
**/
public static int getVRM(String systemName, boolean useSSL) throws AS400SecurityException, IOException {
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting vrm for system: " + systemName + ", use SSL:", useSSL);
return AS400ImplRemote.getVRM(systemName, useSSL);
}
/**
* Returns the version, release, and modification level for the system.
*
* A connection is required to the system to retrieve this information. If a connection has not been established,
* one is created to retrieve the system information.
*
* @return The high 16-bit is the version, the next 8 bits is the release, and the low 8 bits is the modification
* level. Thus version 5, release 1, modification level 0, returns 0x00050100.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
**/
public int getVRM() throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting VRM.");
if (signonInfo_ == null)
{
chooseImpl();
signon(false);
}
int vrm = signonInfo_.version.getVersionReleaseModification();
if (Trace.traceOn_)
{
byte[] vrmBytes = new byte[4];
BinaryConverter.intToByteArray(vrm, vrmBytes, 0);
Trace.log(Trace.DIAGNOSTIC, "VRM:", vrmBytes);
}
return vrm;
}
/**
* Sets the VRM for the object, creating a signonInfo as needed
*
*/
protected void setVRM(int v, int r, int m)
{
if (signonInfo_ == null)
signonInfo_ = new SignonInfo((v << 16 ) + (r << 8) + m);
else
signonInfo_.version.setVersionReleaseModification((v << 16) + (r << 8) + m);
if (impl_ != null)
impl_.setVRM(v,r,m);
}
/**
* Initialize conversion table for the given CCSID. The default EBCDIC to unicode converters are not shipped with
* some browsers. This method can be used to check and download converters if they are not available locally.
*
* @param ccsid the CCSID for the conversion table to initialize.
* @throws UnsupportedEncodingException If the Character Encoding is not supported.
**/
public void initializeConverter(int ccsid) throws UnsupportedEncodingException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Initializing converter for CCSID:", ccsid);
chooseImpl();
try
{
signon(false);
impl_.newConverter(ccsid);
}
catch (Exception e)
{
Trace.log(Trace.WARNING, "Error initializing converter:", e);
throw new UnsupportedEncodingException();
}
}
/**
* Indicates if any service is currently connected through this object.
*
* A service is considered "connected" if connectService() has been called, or an implicit connect has been done by
* the service, and disconnectService() or disconnectAllServices() has not been called. If the most recent attempt
* to contact the service failed with an exception, the service is considered disconnected.
*
* @return true if any service is connected; false otherwise.
* @see #isConnectionAlive
**/
public boolean isConnected()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Checking for any service connection...");
boolean flag = false;
if ( isConnected(AS400.HOSTCNN) || isConnected(AS400.FILE) || isConnected(AS400.PRINT)
|| isConnected(AS400.COMMAND) || isConnected(AS400.DATAQUEUE) || isConnected(AS400.DATABASE)
|| isConnected(AS400.RECORDACCESS) || isConnected(AS400.CENTRAL) || isConnected(AS400.SIGNON) )
flag = true;
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Is a service connected? " + flag);
return flag;
}
/**
* Indicates if a service is currently connected through this object.
*
* A service is considered "connected" if connectService() has been called, or an implicit connect has been done by
* the service, and disconnectService() or disconnectAllServices() has not been called. If the most recent attempt
* to contact the service failed with an exception, the service is considered disconnected.
*
* @param service The name of the service. Valid services are:
*
* - {@link #FILE FILE} - IFS file classes.
*
- {@link #PRINT PRINT} - print classes.
*
- {@link #COMMAND COMMAND} - command and program call classes.
*
- {@link #DATAQUEUE DATAQUEUE} - data queue classes.
*
- {@link #DATABASE DATABASE} - JDBC classes.
*
- {@link #RECORDACCESS RECORDACCESS} - record level access classes.
*
- {@link #CENTRAL CENTRAL} - license management classes.
*
- {@link #SIGNON SIGNON} - sign-on classes.
*
- {@link #HOSTCNN HOSTCNN} - host connection classes.
*
* @return true if service is connected; false otherwise.
* @exception ExtendedIllegalArgumentException If service is not valid.
* @see #isConnectionAlive
**/
public boolean isConnected(int service)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Checking for service connection:", service);
if (service < 0 || service > 8)
throw new ExtendedIllegalArgumentException("service (" + service + ")", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID);
boolean connected = (impl_ == null) ? false : impl_.isConnected(service);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Service connection:", connected);
return connected;
}
/**
* Tests the connection to the system, to verify that it is still working. This is similar in concept to "pinging"
* the system over the connection. If no services have been connected, this method returns false; it doesn't
* implicitly connect services.
*
* Note: This method is not fully supported until IBM i 7.1. If running to IBM i 6.1 or lower, then the
* behavior of this method matches that of {@link #isConnected() isConnected()}, and therefore may incorrectly
* return true if the connection has failed recently.
*
* Note: If the only service connected is {@link #RECORDACCESS RECORDACCESS}, then this method defaults to the
* behavior of {@link #isConnected() isConnected()}.
*
* @return true if the connection is still working; false otherwise.
* @see #isConnected
* @see AS400JPing
**/
public boolean isConnectionAlive()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Testing connection...");
boolean alive = (impl_ == null) ? false : impl_.isConnectionAlive();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Connection status:", alive);
return alive;
}
/**
* Tests the connection to a service on the system, to verify that it is still working. This is similar in concept
* to "pinging" the system over the connection. If no services have been connected, this method returns false; it
* doesn't implicitly connect services.
*
* Note: This method is not fully supported until IBM i 7.1. If running to IBM i 6.1 or lower, then the
* behavior of this method matches that of {@link #isConnected() isConnected()}, and therefore may incorrectly
* return true if the connection has failed recently.
*
* Note: If the specified service is {@link #RECORDACCESS RECORDACCESS}, then this method defaults to the behavior
* of {@link #isConnected() isConnected()}.
*
* @param service The name of the service. Valid services are:
*
* - {@link #FILE FILE} - IFS file classes.
*
- {@link #PRINT PRINT} - print classes.
*
- {@link #COMMAND COMMAND} - command and program call classes.
*
- {@link #DATAQUEUE DATAQUEUE} - data queue classes.
*
- {@link #DATABASE DATABASE} - JDBC classes.
*
- {@link #RECORDACCESS RECORDACCESS} - record level access classes.
*
- {@link #CENTRAL CENTRAL} - license management classes.
*
- {@link #SIGNON SIGNON} - sign-on classes.
*
- {@link #HOSTCNN HOSTCNN} - host connection classes.
*
* @return true if the connection to the service is still working; false otherwise.
* @see #isConnected
* @see AS400JPing
**/
public boolean isConnectionAlive(int service)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Testing connection...");
boolean alive = (impl_ == null) ? false : impl_.isConnectionAlive(service);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Connection status:", alive);
return alive;
}
/**
* Returns the sign-on prompting mode for this object. If true, then messages are displayed. If warnings or errors
* occur, the sign-on and change password dialogs are displayed if needed. If false, warnings and errors result in
* exceptions, and password dialogs are not displayed. The caller has to provide the user ID and password.
*
* @return true if using GUI; false otherwise.
**/
public boolean isGuiAvailable()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Checking if GUI is available:", guiAvailable_);
return guiAvailable_;
}
/**
* Indicates if this object is representing the system you are currently running on.
*
* @return true if you are running on the local system; false otherwise.
**/
public boolean isLocal()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Checking if local:", systemNameLocal_);
return systemNameLocal_;
}
/**
* When your Java program runs on the system, some Toolbox classes access data via a call to an API instead of
* making a socket call to the system. There are minor differences in the behavior of the classes when they use API
* calls instead of socket calls. If your program is affected by these differences you can check whether the Toolbox
* classes will use socket calls instead of API calls by using this method.
*
* @return true if you have indicated that the services must use sockets; false otherwise.
**/
public boolean isMustUseSockets()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Checking if must use sockets:", mustUseSockets_);
return mustUseSockets_;
}
/**
* Indicates if checkboxes should be shown on the sign-on dialog.
*
* @return true if checkboxes should be shown; false otherwise.
**/
public boolean isShowCheckboxes()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Checking if checkboxes are shown:", showCheckboxes_);
return showCheckboxes_;
}
// Check if systemName refers to the system we are running on.
private static boolean isSystemNameLocal(String systemName)
{
if (systemName.equalsIgnoreCase("localhost"))
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "System name is 'localhost'.");
return true;
}
try
{
InetAddress localInet = InetAddress.getLocalHost();
InetAddress[] remoteInet = InetAddress.getAllByName(systemName);
for (int i = 0; i < remoteInet.length; ++i)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Comparing local address " + localInet + " to " + remoteInet[i]);
if (localInet.equals(remoteInet[i]))
return true;
}
}
catch (UnknownHostException e) {
Trace.log(Trace.ERROR, "Error retrieving host address information:", e);
}
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "System name is not local.");
return false;
}
/**
* Indicates whether threads are used in communication with the host servers.
*
* @return true if threads are used; false otherwise.
**/
public boolean isThreadUsed()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Checking if thread is used:", threadUsed_);
return threadUsed_;
}
/**
* Indicates if the default user should be used by this object. If the default user is not used and a user ID was
* not specified on the constructor, then the user will be prompted for a user ID.
*
* @return true if default user should be used; false otherwise.
**/
public boolean isUseDefaultUser()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Checking if default user is used:", useDefaultUser_);
return useDefaultUser_;
}
/**
* Indicates if the password cache is being used by this object. If the password cache is not used, the user will
* always be prompted for password if one was not provided.
*
* @return true if password cache is being used; false otherwise.
**/
public boolean isUsePasswordCache()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Checking if password cache is used:", usePasswordCache_);
return usePasswordCache_;
}
/**
* Is the AS400 object configured to use a pass phrase
*
* @return true if pass phrase can be used
* @throws AS400SecurityException If a security or authority error occurs.
* @throws IOException If an error occurs while communicating with the system.
*/
public boolean isUsePassphrase() throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Checking if use password phrase");
chooseImpl();
signon(false);
boolean ret = false;
if (impl_ instanceof AS400ImplRemote)
ret = ((AS400ImplRemote)impl_).getPasswordType();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Use password phrase: " + ret);
return ret;
}
// Load the specified implementation object. Exceptions are swallowed, null is returned if the object cannot be loaded.
static Object loadImpl(String impl)
{
if (impl.indexOf ('.') == -1)
impl = "com.ibm.as400.access." + impl;
if (Trace.traceOn_ && alreadyCheckedForMultipleVersions_++ < 10)
{
Trace.log(Trace.DIAGNOSTIC, "Checking for multiple Toolbox versions.");
try
{
String thisFileName = "com/ibm/as400/access/AS400.class";
String loadFileName = impl.replace('.', '/') + ".class";
ClassLoader thisLoader = Class.forName(CLASSNAME).getClassLoader();
ClassLoader loadLoader = Class.forName(impl).getClassLoader();
if (thisLoader != null && loadLoader != null)
{
URL thisUrl = thisLoader.getResource(thisFileName);
URL loadUrl = loadLoader.getResource(loadFileName);
if (thisUrl != null && loadUrl != null)
{
String thisPath = thisUrl.getPath();
String loadPath = loadUrl.getPath();
Trace.log(Trace.DIAGNOSTIC, "Path of AS400 class:", thisPath);
Trace.log(Trace.DIAGNOSTIC, "Path of loaded impl class:", loadPath);
String thisDirPath = (thisPath.length() <= thisFileName.length()) ? "" : thisPath.substring(0, thisPath.length() - thisFileName.length() - 1);
String loadDirPath = (loadPath.length() <= loadFileName.length()) ? "" : loadPath.substring(0, loadPath.length() - loadFileName.length() - 1);
if (!thisDirPath.equals(loadDirPath))
{
Trace.log(Trace.WARNING, "Toolbox classes found in two different locations: " + thisDirPath + " and " + loadDirPath);
}
}
}
}
catch (ClassNotFoundException e) {
Trace.log(Trace.DIAGNOSTIC, "Class not found:", e.getMessage());
}
catch (Throwable e) {
Trace.log(Trace.DIAGNOSTIC, e);
}
}
try {
return Class.forName(impl).newInstance();
} catch (ClassNotFoundException e1) {
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Class not found:", e1.getMessage());
} catch (IllegalAccessException e2) {
Trace.log(Trace.ERROR, "Unexpected IllegalAccessException:", e2);
} catch (InstantiationException e3) {
Trace.log(Trace.ERROR, "Unexpected InstantiationException:", e3);
}
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Load of implementation failed:", impl);
return null;
}
// Load the appropriate implementation object.
// param impl1 fully package named class name for native implementation.
// param impl2 fully package named class name for remote implementation.
Object loadImpl(String impl1, String impl2)
{
if (canUseNativeOptimizations())
{
Object impl = loadImpl(impl1);
if (impl != null) return impl;
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Load of native implementation '" + impl1 + "' failed, attempting to load remote implementation.");
}
Object impl = loadImpl(impl2);
if (impl != null) return impl;
Trace.log(Trace.DIAGNOSTIC, "Load of remote implementation '" + impl2 + "' failed.");
throw new ExtendedIllegalStateException(impl2, ExtendedIllegalStateException.IMPLEMENTATION_NOT_FOUND);
}
// Load the appropriate implementation object when only remote or proxy implementations are involved.
// param impl1 fully package named class name for remote implementation.
// param impl2 fully package named class name for proxy implementation.
Object loadImpl2(String impl1, String impl2)
{
if (proxyServer_.length() > 0)
{
synchronized (this)
{
if (proxyClientConnection_ == null)
proxyClientConnection_ = new ProxyClientConnection(proxyServer_, useSSLConnection_);
}
ProxyImpl proxyImpl = (ProxyImpl)loadImpl(impl2);
if (proxyImpl != null)
{
proxyImpl.construct((ProxyClientConnection)proxyClientConnection_);
return proxyImpl;
}
}
Object impl = loadImpl(impl1);
if (impl != null) return impl;
Trace.log(Trace.DIAGNOSTIC, "Load of remote implementation '" + impl1 + "' failed.");
throw new ExtendedIllegalStateException(impl1, ExtendedIllegalStateException.IMPLEMENTATION_NOT_FOUND);
}
// Load the appropriate implementation object when a remote, proxy, or native implementations are involved.
// param impl1 fully package named class name for native implementation.
// param impl2 fully package named class name for remote implementation.
// param impl3 fully package named class name for proxy implementation.
Object loadImpl3(String impl1, String impl2, String impl3)
{
if (proxyServer_.length() > 0)
{
synchronized (this)
{
if (proxyClientConnection_ == null)
proxyClientConnection_ = new ProxyClientConnection(proxyServer_, useSSLConnection_);
}
ProxyImpl proxyImpl = (ProxyImpl)loadImpl(impl3);
if (proxyImpl != null)
{
proxyImpl.construct((ProxyClientConnection)proxyClientConnection_);
return proxyImpl;
}
}
if (canUseNativeOptimizations())
{
Object impl = loadImpl(impl1);
if (impl != null) return impl;
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Load of native implementation '" + impl1 + "' failed, attempting to load remote implementation.");
}
Object impl = loadImpl(impl2);
if (impl != null) return impl;
Trace.log(Trace.DIAGNOSTIC, "Load of remote implementation '" + impl2 + "' failed.");
throw new ExtendedIllegalStateException(impl2, ExtendedIllegalStateException.IMPLEMENTATION_NOT_FOUND);
}
// State machine constants for running through sign-on prompts.
private static final int FINISHED = 0;
private static final int VALIDATE = 1;
private static final int PROMPT = 2;
// Maximum number of iterations of the state machine before we suspect infinite loop.
private static final int MAX_ITERATIONS = 20; // Future enhancement: Make this configurable
// Run through the various prompts for signon.
private void promptSignon() throws AS400SecurityException, IOException
{
if (signingOn_)
{
Trace.log(Trace.ERROR, "AS400.promptSignon() called while already signing on. SignonHandler may have called a prohibited method.");
throw new ExtendedIllegalStateException(ExtendedIllegalStateException.SIGNON_ALREADY_IN_PROGRESS);
}
try
{
signingOn_ = true; // Detect/prevent recursion.
boolean reconnecting = (signonInfo_ != null); // Is this a reconnection.
// Start in validate state.
int pwState = VALIDATE;
SignonHandler soHandler = getSignonHandler();
// If something isn't set, go to prompt state.
if (credVault_.getType() == AUTHENTICATION_SCHEME_PASSWORD
&& (systemName_.length() == 0 || userId_.length() == 0 || credVault_.isEmpty()
|| !(soHandler instanceof ToolboxSignonHandler) || forcePrompt_))
{
pwState = PROMPT;
}
int counter = 0; // Loop counter to detect infinite looping.
boolean proceed = true;
do
{
counter++;
try
{
switch (pwState)
{
case VALIDATE:
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Validate security...");
sendSignonRequest();
break;
case PROMPT:
if(!isGuiAvailable() && forcePrompt_)
{
//JDBC flagged id/pass as invalid and set forcePrompt, but GUI not available
//So don't even try to authenticate because it could be a non-safe password.
Trace.log(Trace.ERROR, "No GUI available for signon dialog.");
handlerCanceled_ = true; // Don't submit exception to handler.
throw new AS400SecurityException(AS400SecurityException.SIGNON_CHAR_NOT_VALID);
}
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Calling SignonHandler...");
// If bytes_ has not been set, tell the handler something is missing.
SignonEvent soEvent = new SignonEvent(this, reconnecting);
proceed = soHandler.connectionInitiated(soEvent, credVault_.isEmpty());
if (!proceed)
{
// User canceled.
Trace.log(Trace.DIAGNOSTIC, "User canceled.");
handlerCanceled_ = true; // Don't submit exception to handler.
throw new AS400SecurityException(AS400SecurityException.SIGNON_CANCELED);
}
sendSignonRequest();
// See if we should cache the password.
if (isUsePasswordCache() && credVault_.getType() == AUTHENTICATION_SCHEME_PASSWORD)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting password cache entry from SignonHandler...");
setCacheEntry(systemName_, userId_, credVault_);
}
break;
default: // This should never happen.
Trace.log(Trace.ERROR, "Invalid password prompt state:", pwState);
throw new InternalErrorException(InternalErrorException.SECURITY_INVALID_STATE, pwState);
}
// Check for number of days to expiration, and warn if within threshold.
if ((!skipSignonServer_) && isInPasswordExpirationWarningDays()) /*@V1C*/
{
SignonEvent soEvent = new SignonEvent(this, reconnecting);
proceed = soHandler.passwordAboutToExpire(soEvent, getDaysToExpiration());
if (!proceed)
{
handlerCanceled_ = true; // Don't submit exception to handler.
throw new AS400SecurityException(AS400SecurityException.SIGNON_CANCELED);
}
}
pwState = FINISHED; // If we got this far, we're done.
}
catch (AS400SecurityException e)
{
if (handlerCanceled_) throw e; // Handler already gave up on this event.
Trace.log(Trace.ERROR, "Security exception in sign-on:", e);
SignonEvent soEvent = new SignonEvent(this, reconnecting, e);
switch (e.getReturnCode())
{
case AS400SecurityException.PASSWORD_EXPIRED:
proceed = soHandler.passwordExpired(soEvent);
break;
case AS400SecurityException.PASSWORD_NOT_SET:
proceed = soHandler.passwordMissing(soEvent);
break;
case AS400SecurityException.PASSWORD_INCORRECT:
case AS400SecurityException.PASSWORD_OLD_NOT_VALID:
proceed = soHandler.passwordIncorrect(soEvent);
break;
case AS400SecurityException.PASSWORD_LENGTH_NOT_VALID:
case AS400SecurityException.PASSWORD_NEW_TOO_LONG:
case AS400SecurityException.PASSWORD_NEW_TOO_SHORT:
proceed = soHandler.passwordLengthIncorrect(soEvent);
break;
case AS400SecurityException.PASSWORD_INCORRECT_USERID_DISABLE:
proceed = soHandler.userIdAboutToBeDisabled(soEvent);
break;
case AS400SecurityException.USERID_UNKNOWN:
proceed = soHandler.userIdUnknown(soEvent);
break;
case AS400SecurityException.USERID_DISABLE:
proceed = soHandler.userIdDisabled(soEvent);
break;
default:
soHandler.exceptionOccurred(soEvent); // Handler rethrows if can't handle.
}
if (!proceed) { throw e; }
// Assume handler has corrected any incorrect values. Prepare to try again.
pwState = VALIDATE;
}
catch (UnknownHostException e)
{
SignonEvent soEvent = new SignonEvent(this, reconnecting);
proceed = soHandler.systemNameUnknown(soEvent, e);
if (!proceed) { throw e; }
pwState = VALIDATE;
}
}
while (pwState != FINISHED && counter < MAX_ITERATIONS);
if (pwState != FINISHED)
{
Trace.log(Trace.ERROR, "Possible infinite loop while interacting with SignonHandler.");
throw new AS400SecurityException(AS400SecurityException.SIGNON_REQUEST_NOT_VALID);
}
}
finally
{
signingOn_ = false;
forcePrompt_ = false; //@prompt
}
}
// Help de-serialize the object.
private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "De-serializing AS400 object.");
in.defaultReadObject();
construct();
systemNameLocal_ = resolveSystemNameLocal(systemName_);
proxyServer_ = resolveProxyServer("");
// proxyClientConnection_ can stay null.
ccsid_ = 0;
// connectionListeners_ can stay null.
// dispatcher_ can stay null.
// propertyChangeListeners_ can stay null.
// vetoableChangeListeners_ can stay null.
propertiesFrozen_ = false;
// impl_ can stay null.
// signonInfo_ can stay null.
// Default to password authentication, just like we would if
// an AS400 object was constructed with no parameters.
credVault_ = new PasswordVault();
}
/**
* Removes a listener from the connection event list.
*
* @param listener The listener object.
**/
public void removeConnectionListener(ConnectionListener listener)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Removing connection listener.");
if (listener == null)
throw new NullPointerException("listener");
synchronized (this)
{
// If we have listeners.
if (connectionListeners_ != null)
{
connectionListeners_.removeElement(listener);
// If we have a connection, and we're now out of listeners.
if (impl_ != null && connectionListeners_.isEmpty())
{
// Remove the dispatcher.
impl_.removeConnectionListener(dispatcher_);
}
}
}
}
/**
* Removes the default user for the given system name.
*
* @param systemName The name of the IBM i system.
**/
public static void removeDefaultUser(String systemName)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Removing the default user, system name:", systemName);
if (systemName == null)
throw new NullPointerException("systemName");
AS400.defaultUsers.remove(resolveSystem(systemName));
}
/**
* Removes the password cache entry associated with this system name and user ID. Only applies within this Java
* virtual machine.
*
* @param systemName The name of the IBM i system.
* @param userId The user profile name.
* @exception ExtendedIllegalArgumentException If userId length is not valid.
**/
public static void removePasswordCacheEntry(String systemName, String userId)
{
boolean isLocalHost = false;
String longName = null;
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Removing password cache entry, system name: " + systemName + " user ID: " + userId);
if (systemName == null)
throw new NullPointerException("systemName");
if (userId == null)
throw new NullPointerException("userId");
if (userId.length() > 10)
throw new ExtendedIllegalArgumentException("userId (" + userId + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
systemName = resolveSystem(systemName);
boolean localHost = systemName.equals("localhost");
if (localHost)
{
isLocalHost = true;
try {
systemName = InetAddress.getLocalHost().getHostName();
} catch (Exception e) { /* ignore */ }
} else {
// Note. The check to see if the current system was also local host was
// done in resolveSystem.
}
int dotIndex = systemName.indexOf(".");
if (dotIndex > 0) {
longName = systemName;
systemName = systemName.substring(0,dotIndex);
}
if (isTurkish()) {
userId = userId.toUpperCase(Locale.ENGLISH);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "This system locale is Turkish, userId.toUpperCase(Locale.ENGLISH)");
}
userId = resolveUserId(userId.toUpperCase());
synchronized (AS400.systemList)
{
for (int i = AS400.systemList.size() - 1; i >= 0; i--)
{
Object[] secobj = (Object[])AS400.systemList.elementAt(i);
if (systemName.equalsIgnoreCase((String)secobj[0]) && userId.equals(secobj[1]))
AS400.systemList.removeElementAt(i);
else if (isLocalHost && "localhost".equalsIgnoreCase((String)secobj[0]) && userId.equals(secobj[1]))
AS400.systemList.removeElementAt(i);
else if (longName != null && longName.equalsIgnoreCase((String)secobj[0]) && userId.equals(secobj[1]))
AS400.systemList.removeElementAt(i);
}
}
}
/**
* Removes a property changed listener from the listener list.
*
* @param listener The listener object.
**/
public void removePropertyChangeListener(PropertyChangeListener listener)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Removing property change listener.");
if (listener == null)
throw new NullPointerException("listener");
// If we have listeners.
if (propertyChangeListeners_ != null)
propertyChangeListeners_.removePropertyChangeListener(listener);
}
/**
* Removes a listener from the veto list.
*
* @param listener The listener object.
**/
public void removeVetoableChangeListener(VetoableChangeListener listener)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Removing vetoable change listener.");
if (listener == null)
throw new NullPointerException("listener");
// If we have listeners.
if (vetoableChangeListeners_ != null)
vetoableChangeListeners_.removeVetoableChangeListener(listener);
}
/**
* Disconnects all services, and clears the sign-on information. This intent of this method is to "wipe the slate
* clean" for this AS400 object, enabling connection properties to be subsequently changed.
*
* Note: A call to resetAllServices() results in the stay-alive seconds value to be reset to zero. You will
* need to invoke the setStayAlive() method to re-enable the stay-alive functionality.
*
* @see #disconnectAllServices
* @see #setStayAlive(long)
**/
public synchronized void resetAllServices()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Resetting all services.");
setStayAlive(0);
disconnectAllServices();
disconnectService(AS400.HOSTCNN);
signonInfo_ = null;
propertiesFrozen_ = false;
ccsid_ = 0;
}
// Resolves the proxy server name. If it is not specified, then look it up in the system properties. Returns empty string if not set.
private static String resolveProxyServer(String proxyServer)
{
if (proxyServer.length() == 0)
{
proxyServer = SystemProperties.getProperty(SystemProperties.AS400_PROXY_SERVER);
if (proxyServer == null) return "";
}
return proxyServer;
}
// If connecting to local system, make systemName "localhost".
static String resolveSystem(String systemName)
{
// First, see if we are running on IBM i.
if (AS400.onAS400)
{
// If system name is null, then make it a localhost.
if (systemName.length() == 0)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Resolving initial system name to 'localhost'.");
return "localhost";
}
else if (isSystemNameLocal(systemName))
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Resolving system name to 'localhost'.");
return "localhost";
}
}
return systemName;
}
// Convenience method to determine if systemName is local system.
static boolean resolveSystemNameLocal(String systemName)
{
if (AS400.onAS400)
if (systemName.length() == 0 || isSystemNameLocal(systemName)) return true;
return false;
}
// If on the system, resolve user ID to current user ID.
static String resolveUserId(String userId)
{
// Resolve user ID, for someone using user ID/password.
return resolveUserId(userId, AUTHENTICATION_SCHEME_PASSWORD, false);
}
private static boolean currentUserAvailable = true;
private static boolean currentUserTried = false;
static boolean currentUserAvailable()
{
if (!currentUserTried)
{
try
{
Class.forName("com.ibm.as400.access.CurrentUser");
}
catch (Throwable t)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "CurrentUser class is not available:", t);
currentUserAvailable = false;
}
currentUserTried = true;
}
return currentUserAvailable;
}
// If on the system, resolve user ID to current user ID.
static String resolveUserId(String userId, int authScheme, boolean mustUseSuppliedProfile)
{
// First, see if we are running on the system.
if (AS400.onAS400 && !mustUseSuppliedProfile && currentUserAvailable())
{
boolean tryToGetCurrentUserID = false;
// If user ID is not set and we're using user ID/password, then we get it and set it up.
if (userId.length() == 0 && authScheme == AUTHENTICATION_SCHEME_PASSWORD)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Resolving initial user ID.");
tryToGetCurrentUserID = true;
}
// If we are running on the system, then *CURRENT for user ID means we want to connect using current user ID.
if (userId.equals("*CURRENT"))
{
// Get current user ID and use it.
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Replacing *CURRENT as user ID.");
tryToGetCurrentUserID = true;
}
if (tryToGetCurrentUserID)
{
String currentUserID = CurrentUser.getUserID(AS400.nativeVRM.getVersionReleaseModification());
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Current user ID:", currentUserID);
if (currentUserID != null) return currentUserID;
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Current user ID information not available, user ID: '" + userId + "'");
}
}
// Prepend Q to numeric user ID.
if (userId.length() > 0 && Character.isDigit(userId.charAt(0)))
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Prepending 'Q' to numeric user ID.");
userId = "Q" + userId;
}
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "User ID: '" + userId + "'");
return userId;
}
// Send sign-on request to sign-on server.
private void sendSignonRequest() throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Signing-on without prompting...");
// No prompting.
if (credVault_.isEmpty() && !userIdMatchesLocal(userId_, mustUseSuppliedProfile_))
throw new AS400SecurityException(AS400SecurityException.PASSWORD_NOT_SET);
// If using GSS tokens, don't bother encoding the authentication info.
if (credVault_.getType() == AUTHENTICATION_SCHEME_GSS_TOKEN)
{
signonInfo_ = impl_.signon(systemName_, systemNameLocal_, userId_, credVault_, gssName_, null);
if (gssCredential_ != null)
impl_.setGSSCredential(gssCredential_);
credVault_.empty(); // GSSToken is single use only.
}
else // Encode the authentication info before sending vault to impl.
{
byte[] proxySeed = new byte[9];
CredentialVault.rng.nextBytes(proxySeed);
CredentialVault tempVault = (CredentialVault)credVault_.clone();
tempVault.storeEncodedUsingExternalSeeds(proxySeed, impl_.exchangeSeed(proxySeed));
if (PASSWORD_TRACE) Trace.log(Trace.DIAGNOSTIC, "AS400 object proxySeed:", proxySeed);
if (skipSignonServer_)
signonInfo_ = impl_.skipSignon(systemName_, systemNameLocal_, userId_, tempVault, gssName_);
else
signonInfo_ = impl_.signon(systemName_, systemNameLocal_, userId_, tempVault, gssName_, additionalAuthenticationFactor_);
}
if (userId_.length() == 0) userId_ = signonInfo_.userId;
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Sign-on completed.");
}
/**
* Sets or resets the identity token for this object. Using this method will clear any previously set authentication
* information.
*
* Note: Authentication via IdentityToken is supported in operating system release V5R3M0 and by PTF in operating
* system releases V5R2M0 and V5R1M0.
*
* @param identityToken The identity token.
**/
public void setIdentityToken(byte[] identityToken)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting identity token.");
if (identityToken == null)
throw new NullPointerException("identityToken");
synchronized (this)
{
credVault_.empty();
credVault_ = new IdentityTokenVault(identityToken);
signonInfo_ = null;
}
}
/**
* Set the additional authentication factor for the AS400 object. This will be used when establishing host server
* connections if the IBM i server supports multifactor authentication.
*
* @param additionalAuthFactor The additional authentication factor.
* @exception ExtendedIllegalArgumentException If additionalAuthFactor length is not valid.
*/
public void setAdditionalAuthenticationFactor(char[] additionalAuthFactor)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting additional authentication factor. Length: "
+ ((additionalAuthFactor == null) ? 0 : additionalAuthFactor.length));
if (additionalAuthFactor == null || additionalAuthFactor.length == 0)
additionalAuthenticationFactor_ = null;
else
{
if (additionalAuthFactor.length > ProfileTokenCredential.MAX_ADDITIONALAUTHENTICATIONFACTOR_LENGTH)
throw new ExtendedIllegalArgumentException("additionalAuthFactor", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
additionalAuthenticationFactor_ = Arrays.copyOf(additionalAuthFactor, additionalAuthFactor.length);
}
if (impl_ != null)
impl_.setAdditionalAuthenticationFactor(additionalAuthenticationFactor_);
}
// Store information in password cache.
private static void setCacheEntry(String systemName, String userId, CredentialVault pwVault)
{
synchronized (AS400.systemList)
{
// Remove any duplicates in the list and add to the list.
for (int i = AS400.systemList.size() - 1; i >= 0; i--)
{
Object[] curPtr = (Object[])AS400.systemList.elementAt(i);
if (systemName.equalsIgnoreCase((String)curPtr[0]) && userId.equals(curPtr[1]))
{
// Found duplicate, remove it.
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Adding password cache entry, removing previous entry.");
AS400.systemList.removeElementAt(i);
}
}
// Now add the new one.
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Adding password cache entry for "+systemName+":"+userId+".");
AS400.systemList.addElement(new Object[] {systemName, userId, pwVault.clone()} );
}
}
/**
* Sets the CCSID to be used for this object. The CCSID property cannot be changed once a connection to the system
* has been established.
*
* @param ccsid The CCSID to use for this object.
* @exception ExtendedIllegalStateException If a connection has already been made.
* @exception PropertyVetoException If any of the registered listeners vetos the property change.
**/
public void setCcsid(int ccsid) throws PropertyVetoException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting CCSID:", ccsid);
if (propertiesFrozen_)
{
Trace.log(Trace.ERROR, "Cannot set CCSID after connection has been made.");
throw new ExtendedIllegalStateException("ccsid", ExtendedIllegalStateException.PROPERTY_NOT_CHANGED);
}
if (propertyChangeListeners_ == null && vetoableChangeListeners_ == null)
ccsid_ = ccsid;
else
{
Integer oldValue = Integer.valueOf(ccsid_);
Integer newValue = Integer.valueOf(ccsid);
if (vetoableChangeListeners_ != null)
vetoableChangeListeners_.fireVetoableChange("ccsid", oldValue, newValue);
ccsid_ = ccsid;
if (propertyChangeListeners_ != null)
propertyChangeListeners_.firePropertyChange("ccsid", oldValue, newValue);
}
}
/**
* Sets the relational database name (RDB name) used for record-level access (DDM) connections. The RDB name
* corresponds to the independent auxiliary storage pool (IASP) that it is using on the system. The RDB name cannot
* be changed while this object is actively connected to the {@link #RECORDACCESS RECORDACCESS} service; you must
* call {@link #disconnectService(int) AS400.disconnectService(AS400.RECORDACCESS)} first.
*
* @param ddmRDB The name of the IASP or RDB to use, or null to indicate the default system ASP should be used.
* @see #isConnected(int)
* @see #getDDMRDB
* @exception ExtendedIllegalArgumentException If ddmRDB length is not valid.
* @exception ExtendedIllegalStateException If a connection has already been made.
**/
public void setDDMRDB(String ddmRDB)
{
if (propertiesFrozen_)
{
Trace.log(Trace.ERROR, "Cannot set RDB name after connection has been made.");
throw new ExtendedIllegalStateException("ddmRDB", ExtendedIllegalStateException.PROPERTY_NOT_CHANGED);
}
if (ddmRDB != null && ddmRDB.length() > 18)
throw new ExtendedIllegalArgumentException("ddmRDB", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
if (isConnected(RECORDACCESS))
throw new ExtendedIllegalStateException("ddmRDB", ExtendedIllegalStateException.PROPERTY_NOT_SET);
ddmRDB_ = ((ddmRDB == null) ? null : ddmRDB.toUpperCase());
}
/**
* Sets the default sign-on handler, globally across the JVM. The specified handler object will be called at runtime
* if any AS400 object needs to obtain additional signon information, and a sign-on handler has not been set on the
* AS400 object via {@link #setSignonHandler setSignonHandler()}.
* Users are advised to implement the default sign-on handler in a thread-safe manner, since it may occasionally be
* in simultaneous use by multiple threads.
* If a default sign-on handler is not set, then the name of the default sign-on handler class is retrieved from the
* com.ibm.as400.access.AS400.signonHandler system property.
*
* If not specified, an internal AWT-based sign-on handler is used.
*
* Note: This property may also be set by specifying a fully-qualified class name in Java system property
* com.ibm.as400.access.AS400.signonHandler
*
* @param handler The sign-on handler. Specifying null will reset the default sign-on handler to the
* internal AWT-based handler.
* @see #getDefaultSignonHandler
**/
public static void setDefaultSignonHandler(SignonHandler handler)
{
if (Trace.traceOn_)
{
if (handler == null) Trace.log(Trace.DIAGNOSTIC, "Setting the default sign-on handler to null.");
else if (defaultSignonHandler_ != null) Trace.log(Trace.DIAGNOSTIC, "Replacing default sign-on handler, formerly an instance of " + defaultSignonHandler_.getClass().getName());
}
defaultSignonHandler_ = handler;
}
/**
* Sets the default user for a given system name. The default user is the user ID that is used to connect if a user
* ID is not provided for that system name. There can be only one default user per system name. Once the default
* user is set, it cannot be overridden. To change the default user, the caller should remove the default user and
* then set it.
*
* @param systemName The name of the IBM i system.
* @param userId The user profile name.
* @return true if default user has been set; false otherwise.
* @exception ExtendedIllegalArgumentException If userId length is not valid.
**/
public static boolean setDefaultUser(String systemName, String userId)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting the default user, system name: '" + systemName + "' user ID: '" + userId + "'");
if (systemName == null)
throw new NullPointerException("systemName");
if (userId == null)
throw new NullPointerException("userId");
if (userId.length() > 10)
throw new ExtendedIllegalArgumentException("userId (" + userId + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
systemName = resolveSystem(systemName);
if (isTurkish()) {
userId = userId.toUpperCase(Locale.ENGLISH);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "This system locale is Turkish, userId.toUpperCase(Locale.ENGLISH)");
}
userId = resolveUserId(userId.toUpperCase());
synchronized (AS400.defaultUsers)
{
if (AS400.defaultUsers.get(systemName) == null)
{
AS400.defaultUsers.put(systemName, userId);
return true;
}
}
// Already have a default user, fail the op.
if (Trace.traceOn_) Trace.log(Trace.WARNING, "Default user already set, set default user failed.");
return false;
}
/**
* Sets the GSS manager to be used for all GSS operations.
*
* @param gssMgr The GSS manager object.
**/
public static void setGSSManager(GSSManager gssMgr)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting GSS manager: '" + gssMgr + "'");
gssManager_ = gssMgr;
}
static GSSManager getGSSManager() {
return gssManager_;
}
/**
* Sets the GSS credential for this object. Using this method will set the authentication scheme to
* {@link #AUTHENTICATION_SCHEME_GSS_TOKEN AUTHENTICATION_SCHEME_GSS_TOKEN}. Only one authentication means (Kerberos
* ticket, profile token, identity token, or password) can be used at a single time. Using this method will clear
* any previously set authentication information.
*
* @param gssCredential The GSS credential object.
**/
public void setGSSCredential(GSSCredential gssCredential)
{
if (gssCredential == null)
throw new NullPointerException("gssCredential");
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting GSS credential: '" + gssCredential + "'");
synchronized (this)
{
gssCredential_ = gssCredential;
gssName_ = "";
credVault_.empty();
credVault_ = new GSSTokenVault();
signonInfo_ = null;
if (impl_ != null)
impl_.setGSSCredential(gssCredential_);
}
}
/**
* Sets the option for how the JGSS framework will be used to retrieve a GSS token for authenticating to the system.
* By default, if no password or profile token is set on this object, it will attempt to retrieve a GSS token. If
* that retrieval fails, a sign-on dialog can be presented, or on the system, the current user profile information
* can be used. This option can also be set to only do the GSS token retrieval or to skip the GSS token retrieval.
*
* @param gssOption A constant indicating how GSS will be used. Valid values are:
*
* - {@link #GSS_OPTION_MANDATORY GSS_OPTION_MANDATORY}
*
- {@link #GSS_OPTION_FALLBACK GSS_OPTION_FALLBACK}
*
- {@link #GSS_OPTION_NONE GSS_OPTION_NONE}
*
* @exception ExtendedIllegalArgumentException If gssOption is not valid.
**/
public void setGSSOption(int gssOption)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting GSS option:", gssOption);
if (gssOption < 0 || gssOption > 2)
throw new ExtendedIllegalArgumentException("gssOption (" + gssOption + ")", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID);
gssOption_ = gssOption;
}
/**
* Sets the GSS name for this object. Using this method will set the authentication scheme to
* {@link #AUTHENTICATION_SCHEME_GSS_TOKEN AUTHENTICATION_SCHEME_GSS_TOKEN}. Only one authentication means (Kerberos
* ticket, profile token, identity token, or password) can be used at a single time. Using this method will clear
* any previously set authentication information.
*
* @param gssName The GSS name string.
**/
public void setGSSName(String gssName)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting GSS name: '" + gssName + "'");
if (gssName == null)
throw new NullPointerException("gssName");
synchronized (this)
{
gssName_ = gssName;
gssCredential_ = null;
credVault_.empty();
credVault_ = new GSSTokenVault();
signonInfo_ = null;
}
}
/**
* Sets the environment in which you are running. If guiAvailable is set to true, then prompting may occur during
* sign-on to display error conditions, to prompt for additional information, or to prompt for change password. If
* guiAvailable is set to false, then error conditions or missing information will result in exceptions.
* Applications that are running as IBM i applications or want to control the sign-on user interface may want to run
* with prompting mode set to false. Prompting mode is set to true by default.
*
* Note: This property may also be set by specifying 'true' or 'false' in Java system property
* com.ibm.as400.access.AS400.guiAvailable
*
* @param guiAvailable true to prompt; false otherwise.
* @exception PropertyVetoException If any of the registered listeners vetos the property change.
* @see SignonHandler
**/
public void setGuiAvailable(boolean guiAvailable) throws PropertyVetoException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting GUI available:", guiAvailable);
if (propertyChangeListeners_ == null && vetoableChangeListeners_ == null)
guiAvailable_ = guiAvailable;
else
{
Boolean oldValue = Boolean.valueOf(guiAvailable_);
Boolean newValue = Boolean.valueOf(guiAvailable);
if (vetoableChangeListeners_ != null)
vetoableChangeListeners_.fireVetoableChange("guiAvailable", oldValue, newValue);
guiAvailable_ = guiAvailable;
if (propertyChangeListeners_ != null)
propertyChangeListeners_.firePropertyChange("guiAvailable", oldValue, newValue);
}
}
/**
* Sets the Locale used to set the National Language Version (NLV) on the system. Only the COMMAND, PRINT, and
* DATABASE services accept an NLV. This method will set the NLV based on a mapping from the Locale object to the
* NLV.
*
* @param locale The Locale object.
* @exception ExtendedIllegalStateException If a connection has already been made.
**/
public void setLocale(Locale locale)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting locale: " + locale);
if (locale == null)
throw new NullPointerException("locale");
if (propertiesFrozen_)
{
Trace.log(Trace.ERROR, "Cannot set locale after connection has been made.");
throw new ExtendedIllegalStateException("locale", ExtendedIllegalStateException.PROPERTY_NOT_CHANGED);
}
if (propertyChangeListeners_ == null)
{
locale_ = locale;
nlv_ = ExecutionEnvironment.getNlv(locale_);
}
else
{
Locale oldValue = locale_;
Locale newValue = locale;
locale_ = locale;
nlv_ = ExecutionEnvironment.getNlv(locale_);
propertyChangeListeners_.firePropertyChange("locale", oldValue, newValue);
}
}
/**
* Sets the Locale and a specific National Language Version (NLV) to send to the system. Only the COMMAND, PRINT,
* and DATABASE services accept an NLV.
*
* @param locale The Locale object.
* @param nlv The NLV.
* @exception ExtendedIllegalStateException If a connection has already been made.
**/
public void setLocale(Locale locale, String nlv)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting locale: " + locale + ", nlv: " + nlv_);
if (locale == null)
throw new NullPointerException("locale");
if (nlv == null)
throw new NullPointerException("nlv");
if (propertiesFrozen_)
{
Trace.log(Trace.ERROR, "Cannot set locale after connection has been made.");
throw new ExtendedIllegalStateException("locale", ExtendedIllegalStateException.PROPERTY_NOT_CHANGED);
}
locale_ = locale;
nlv_ = nlv;
}
/**
* Sets this object to attempt to add the appropriate secondary language library to the library list, when running
* on the system. The default is false. Setting the language library will ensure that any system error messages that
* are returned, will be returned in the appropriate national language for the client locale. If the user profile
* has insufficient authority to call CHGSYSLIBL, an error entry will appear in the job log, and the Toolbox will
* disregard the error and proceed normally.
*
* Note: This property may also be set by specifying 'true' or 'false' in Java system property
* com.ibm.as400.access.AS400.mustAddLanguageLibrary
*
* @param mustAddLanguageLibrary true to add language library; false otherwise.
* @exception ExtendedIllegalStateException If a connection has already been made.
**/
public void setMustAddLanguageLibrary(boolean mustAddLanguageLibrary)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting must add language library:", mustAddLanguageLibrary_);
if (propertiesFrozen_)
{
Trace.log(Trace.ERROR, "Cannot set must add language library after connection has been made.");
throw new ExtendedIllegalStateException("mustAddLanguageLibrary", ExtendedIllegalStateException.PROPERTY_NOT_CHANGED);
}
mustAddLanguageLibrary_ = mustAddLanguageLibrary;
}
/**
* Indicates whether this object will attempt to add the appropriate secondary language library to the library list,
* when running on the system.
*
* @return true if you have indicated that the secondary language library must be added; false otherwise.
**/
public boolean isMustAddLanguageLibrary()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Checking if must add language library:", mustAddLanguageLibrary_);
return mustAddLanguageLibrary_;
}
/**
* Sets this object to using sockets. When your Java program runs on the system, some Toolbox classes access data
* via a call to an API instead of making a socket call to the system. There are minor differences in the behavior
* of the classes when they use API calls instead of socket calls. If your program is affected by these differences
* you can force the Toolbox classes to use socket calls instead of API calls by using this method. The default is
* false. The must use sockets property cannot be changed once a connection to the system has been established.
*
* Note: This property may also be set by specifying 'true' or 'false' in Java system property
* com.ibm.as400.access.AS400.mustUseSockets
*
* @param mustUseSockets true to use sockets; false otherwise.
* @exception ExtendedIllegalStateException If a connection has already been made.
**/
public void setMustUseSockets(boolean mustUseSockets)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting 'must use sockets':", mustUseSockets);
if (propertiesFrozen_)
{
Trace.log(Trace.ERROR, "Cannot set 'must use sockets' after connection has been made.");
throw new ExtendedIllegalStateException("mustUseSockets", ExtendedIllegalStateException.PROPERTY_NOT_CHANGED);
}
mustUseSockets_ = mustUseSockets;
}
/**
* Indicates if Internet domain sockets only will be used.
*
* @return true if must use Internet domain sockets only; false otherwise.
**/
public boolean isMustUseNetSockets()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Checking if must use net sockets:", mustUseNetSockets_);
return mustUseNetSockets_;
}
/**
* Sets this object to using Internet domain sockets only. When your Java program runs on the system, some Toolbox
* classes create UNIX domain socket connections. Using this method forces the Toolbox to only use Internet domain
* sockets. The default is false. The must use net sockets property cannot be changed once a connection to the
* system has been established.
*
* Note: This property may also be set by specifying 'true' or 'false' in Java system property
* com.ibm.as400.access.AS400.mustUseNetSockets
*
* @param mustUseNetSockets true to use Internet domain sockets only; false otherwise.
* @exception ExtendedIllegalStateException If a connection has already been made.
**/
public void setMustUseNetSockets(boolean mustUseNetSockets)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting 'must use net sockets':", mustUseNetSockets);
if (propertiesFrozen_)
{
Trace.log(Trace.ERROR, "Cannot set 'must use net sockets' after connection has been made.");
throw new ExtendedIllegalStateException("mustUseNetSockets", ExtendedIllegalStateException.PROPERTY_NOT_CHANGED);
}
mustUseNetSockets_ = mustUseNetSockets;
}
/**
* Indicates if only a supplied profile will be used.
*
* @return true if must use a supplied profile only; false otherwise.
**/
public boolean isMustUseSuppliedProfile()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Checking if must use supplied profile:", mustUseSuppliedProfile_);
return mustUseSuppliedProfile_;
}
/**
* Sets this object to using a supplied profile only. When your Java program runs on the system, the information
* from the currently signed-on user profile can be used. Using this method prevents the Toolbox from retrieving the
* current user profile information. The default is false. The must use supplied profile property cannot be
* changed once a connection to the system has been established.
*
* Note: This property may also be set by specifying 'true' or 'false' in Java system property
* com.ibm.as400.access.AS400.mustUseSuppliedProfile
*
* @param mustUseSuppliedProfile true to use a supplied profile only; false otherwise.
* @exception ExtendedIllegalStateException If a connection has already been made.
**/
public void setMustUseSuppliedProfile(boolean mustUseSuppliedProfile)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting 'must use supplied profile':", mustUseSuppliedProfile);
if (propertiesFrozen_)
{
Trace.log(Trace.ERROR, "Cannot set 'must use supplied profile' after connection has been made.");
throw new ExtendedIllegalStateException("mustUseSuppliedProfile", ExtendedIllegalStateException.PROPERTY_NOT_CHANGED);
}
mustUseSuppliedProfile_ = mustUseSuppliedProfile;
}
/**
* Sets the password for this object. Only one authentication means (Kerberos ticket, profile token, identity token,
* or password) can be used at a single time. Using this method will clear any previously set authentication
* information.
*
* @param password The user profile password.
* @deprecated
**/
@Deprecated
public void setPassword(String password)
{
char[] passwordChars = (password == null) ? null : password.toCharArray();
try {
setPassword(passwordChars);
}
finally {
PasswordVault.clearArray(passwordChars);
}
}
/**
* Sets the password for this object using a char array. The caller is responsible for clearing the array after the
* method returns. Only one authentication means (Kerberos ticket, profile token, identity token, or password) can
* be used at a single time. Using this method will clear any previously set authentication information.
*
* @param password The user profile password.
**/
public void setPassword(char[] password)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting password.");
checkPasswordNullAndLength(password, "password");
synchronized (this)
{
credVault_.empty();
credVault_ = new PasswordVault(password);
signonInfo_ = null;
}
}
/**
* Sets the number of days before password expiration to warn the user.
*
* @param days The number of days before expiration to start the warning. Set to -1 to turn off warning.
**/
public static void setPasswordExpirationWarningDays(int days)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting the password expiration warning days:", days);
AS400.expirationWarning = days;
}
/**
* Sets or resets the profile token for this object. Using this method will clear any previously set authentication
* information.
*
* @param profileToken The profile token.
**/
public void setProfileToken(ProfileTokenCredential profileToken)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting profile token.");
if (profileToken == null)
throw new NullPointerException("profileToken");
synchronized (this)
{
credVault_.empty();
credVault_ = new ProfileTokenVault(profileToken);
signonInfo_ = null;
}
}
/**
* Sets the name and port of the middle-tier machine where the proxy server is running. If this is not set, then the
* name is retrieved from the com.ibm.as400.access.AS400.proxyServer
* system property. The ProxyServer
* must be running on the middle-tier machine.
*
* The name of the middle-tier machine is ignored in a two-tier environment. If no middle-tier machine is specified,
* then it is assumed that no middle-tier will be accessed. The name of the middle-tier machine cannot be changed
* once a connection to this machine has been established.
*
* @param proxyServer The name and port of the proxy server in the format serverName[:port]
. If no port
* is specified, a default will be used.
* @exception ExtendedIllegalStateException If a connection has already been made.
* @exception PropertyVetoException If any of the registered listeners vetos the property change.
**/
public void setProxyServer(String proxyServer) throws PropertyVetoException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting proxy server:", proxyServer);
if (impl_ != null)
{
Trace.log(Trace.ERROR, "Cannot set proxy server after connection has been made.");
throw new ExtendedIllegalStateException("proxyServer", ExtendedIllegalStateException.PROPERTY_NOT_CHANGED);
}
if (propertyChangeListeners_ == null && vetoableChangeListeners_ == null)
proxyServer_ = resolveProxyServer(proxyServer);
else
{
String oldValue = proxyServer_;
String newValue = resolveProxyServer(proxyServer);
if (vetoableChangeListeners_ != null)
vetoableChangeListeners_.fireVetoableChange("proxyServer", oldValue, newValue);
proxyServer_ = newValue;
if (propertyChangeListeners_ != null)
propertyChangeListeners_.firePropertyChange("proxyServer", oldValue, newValue);
}
}
/**
* Sets the service port in the service port table for the specified service for this system name.
*
* @param service The name of the service. Valid services are:
*
* - {@link #FILE FILE} - IFS file classes.
*
- {@link #PRINT PRINT} - print classes.
*
- {@link #COMMAND COMMAND} - command and program call classes.
*
- {@link #DATAQUEUE DATAQUEUE} - data queue classes.
*
- {@link #DATABASE DATABASE} - JDBC classes.
*
- {@link #RECORDACCESS RECORDACCESS} - record level access classes.
*
- {@link #CENTRAL CENTRAL} - license management classes.
*
- {@link #SIGNON SIGNON} - sign-on classes.
*
- {@link #HOSTCNN HOSTCNN} - host-connection classes.
*
* @param port The port to use for this service. The value {@link #USE_PORT_MAPPER USE_PORT_MAPPER} can be used
* to specify that the next connection to this service should ask the port mapper server for the port
* number.
* @exception ExtendedIllegalArgumentException If service or port is not valid.
* @exception ExtendedIllegalStateException If system name has not been set.
**/
public void setServicePort(int service, int port)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting service port, service " + service + ", port " + port);
// Validate parameters.
if (service < 0 || service > 8)
throw new ExtendedIllegalArgumentException("service (" + service + ")", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID);
if (port < -1)
throw new ExtendedIllegalArgumentException("port (" + port + ")", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID);
// Validate state.
if (systemName_.length() == 0 && !systemNameLocal_)
{
Trace.log(Trace.ERROR, "Cannot set service port before system name is set.");
throw new ExtendedIllegalStateException("systemName", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
chooseImpl();
impl_.setServicePort((systemNameLocal_) ? "localhost" : systemName_, service, port);
}
/**
* Sets the ports in the service port table for all the services for this system name to their default values. This
* causes the connections to this system name to use the default ports for those services rather than querying the
* port number through a port mapper connection. The use of this method can reduce the number of connections made to
* the system.
*
* @exception ExtendedIllegalStateException If system name has not been set.
**/
public void setServicePortsToDefault()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting service ports to default.");
// Validate state.
if (systemName_.length() == 0 && !systemNameLocal_)
{
Trace.log(Trace.ERROR, "Cannot set service port to default before system name is set.");
throw new ExtendedIllegalStateException("systemName", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
chooseImpl();
impl_.setServicePortsToDefault((systemNameLocal_) ? "localhost" : systemName_);
}
/**
* Indicates if checkboxes should be shown on the sign-on dialog.
*
* @param showCheckboxes true to show checkboxes; false otherwise.
**/
public void setShowCheckboxes(boolean showCheckboxes)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting show checkboxes:", showCheckboxes);
showCheckboxes_ = showCheckboxes;
}
/**
* Sets the sign-on handler for this AS400 object. The specified handler will be called at runtime if the AS400
* object needs to obtain additional signon information.
* By default, an internal AWT-based implementation is used, if no sign-on handler has been statically set via
* setDefaultSignonHandler().
*
* @param handler The sign-on handler. Specifying null will reset the default sign-on handler to the
* internal AWT-based handler.
* @see #getSignonHandler
* @see #setDefaultSignonHandler
**/
public void setSignonHandler(SignonHandler handler)
{
if (Trace.traceOn_)
{
if (handler == null) Trace.log(Trace.DIAGNOSTIC, "Setting the sign-on handler to null.");
if (signonHandler_ != null) Trace.log(Trace.DIAGNOSTIC, "Sign-on handler was formerly an instance of " + signonHandler_.getClass().getName());
}
signonHandler_ = handler;
}
private volatile long stayAliveMilliSeconds_ = 0;
private class StayAliveThread extends Thread
{
@Override
public void run()
{
// Want to always wake up every 30 seconds if say-alive time greater than that.
// This to ensure that we end thread if stay-alive time set to 0.
// So when whenToPing is zero or less, we actually ping. Otherwise, we loop.
long stayAliveMilliSeconds_original = stayAliveMilliSeconds_;
long whenToPing = stayAliveMilliSeconds_original;
long sleepTime = (stayAliveMilliSeconds_original > 30000) ? 30000 : stayAliveMilliSeconds_original;
while (stayAliveMilliSeconds_ > 0)
{
try
{
sleep(sleepTime);
whenToPing -= sleepTime;
// If stay-alive time changed to zero, let thread end.
if (stayAliveMilliSeconds_ == 0)
break;
if (whenToPing <= 0)
{
whenToPing = stayAliveMilliSeconds_original;
boolean bDATABASE = isConnectionAlive(AS400.DATABASE);
boolean bCOMMAND = isConnectionAlive(AS400.COMMAND);
boolean bDATAQUEUE = isConnectionAlive(AS400.DATAQUEUE);
boolean bFILE = isConnectionAlive(AS400.FILE);
boolean bPRINT = isConnectionAlive(AS400.PRINT);
boolean bHOSTCNN = isConnectionAlive(AS400.HOSTCNN);
if (Trace.traceOn_)
{
Trace.log(Trace.DIAGNOSTIC, "Stayalive status of services: "
+ "DATABASE=" + bDATABASE + ", "
+ "COMMAND=" + bCOMMAND + ", "
+ "DATAQUEUE=" + bDATAQUEUE + ", "
+ "FILE=" + bFILE + ", "
+ "PRINT=" + bPRINT + ", "
+ "HOSTCNN=" + bHOSTCNN);
}
}
if (stayAliveMilliSeconds_original != stayAliveMilliSeconds_)
{
stayAliveMilliSeconds_original = stayAliveMilliSeconds_;
whenToPing = stayAliveMilliSeconds_original;
sleepTime = (stayAliveMilliSeconds_original > 30000) ? 30000 : stayAliveMilliSeconds_original;
}
}
catch (Exception e) {
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Stayalive thread exception ignored. ", e);
}
}
}
}
private StayAliveThread stayAliveThread_;
/**
* Set the stay-alve interval. When enabled, a request is sent at the specified seconds interval to all
* currently opened connections to help keep the connections alive. This is sometimes needed to prevent firewalls
* from dropping stale connections.
*
* This stay-alive functionality only applies to connections to the following host servers: {@link #COMMAND
* COMMAND}, {@link #DATABASE DATABASE}, {@link #DATAQUEUE DATAQUEUE}, {@link #FILE FILE}, {@link #PRINT PRINT}, and
* {@link #HOSTCNN HOSTCNN}.
*
* Notes:
*
* - A background thread is used to ensure the connections stay alive. Any errors that occur while attempting
* to ensure connections are alive are ignored.
*
- If {@link #resetAllServices()} is called on the object, the number of seconds is set to zero. You will
* need to invoke setStayAlive() method to re-enable the stay-alive functionality.
*
*
* @param seconds The number of seconds between requests to the server. If set to zero, then this
* stay-alive capability will not be used.
*
* @exception ExtendedIllegalArgumentException if the value of seconds is negative.
**/
synchronized public void setStayAlive(long seconds)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting stay-alive: " + seconds);
// Validate parameter.
if (seconds < 0)
throw new ExtendedIllegalArgumentException("seconds (" + seconds + ")", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID);
stayAliveMilliSeconds_ = seconds*1000;
if (stayAliveMilliSeconds_ == 0)
stayAliveThread_ = null;
else if (stayAliveThread_ == null || !stayAliveThread_.isAlive())
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Creating stay-alive thread.");
stayAliveThread_ = new StayAliveThread();
stayAliveThread_.setDaemon(true);
stayAliveThread_.start();
}
}
/**
* Sets the socket options the IBM Toolbox for Java will set on its client side sockets. The socket properties
* cannot be changed once a connection to the system has been established.
*
* @param socketProperties The set of socket options to set. The options are copied from this object, not shared.
*
* @exception ExtendedIllegalStateException if a connection has already been made.
**/
public void setSocketProperties(SocketProperties socketProperties)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting socket properties: " + socketProperties);
if (socketProperties == null)
throw new NullPointerException("socketProperties");
if (propertiesFrozen_)
{
Trace.log(Trace.ERROR, "Cannot set socket properties after connection has been made.");
throw new ExtendedIllegalStateException("socketProperties", ExtendedIllegalStateException.PROPERTY_NOT_CHANGED);
}
socketProperties_.copyValues(socketProperties);
}
/**
* Sets the system name for this object. The system name cannot be changed once a connection to the system has been
* established.
*
* @param systemName The name of the IBM i system. Use localhost
to access data locally.
* @exception ExtendedIllegalStateException if a connection has already been made.
* @exception PropertyVetoException If any of the registered listeners vetos the property change.
**/
public void setSystemName(String systemName) throws PropertyVetoException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting system name:", systemName);
if (systemName == null)
throw new NullPointerException("systemName");
if (systemName.equals(systemName_)) return;
if (propertiesFrozen_ && (systemNameLocal_ || systemName_.length() != 0))
{
Trace.log(Trace.ERROR, "Cannot set system name after connection has been made.");
throw new ExtendedIllegalStateException("systemName", ExtendedIllegalStateException.PROPERTY_NOT_CHANGED);
}
if (propertyChangeListeners_ == null && vetoableChangeListeners_ == null)
{
systemName_ = systemName;
systemNameLocal_ = resolveSystemNameLocal(systemName);
}
else
{
String oldValue = systemName_;
String newValue = systemName;
if (vetoableChangeListeners_ != null)
vetoableChangeListeners_.fireVetoableChange("systemName", oldValue, newValue);
systemName_ = systemName;
systemNameLocal_ = resolveSystemNameLocal(systemName);
if (propertyChangeListeners_ != null)
propertyChangeListeners_.firePropertyChange("systemName", oldValue, newValue);
}
}
/**
* Sets whether the IBM Toolbox for Java uses threads in communication with the host servers. The default is true.
* Letting the IBM Toolbox for Java use threads may be beneficial to performance, turning threads off may be
* necessary if your application needs to be compliant with the Enterprise Java Beans specification. The thread used
* property cannot be changed once a connection to the system has been established.
*
*
* Note: This property may also be set by specifying 'true' or 'false' in Java system property
* com.ibm.as400.access.AS400.threadUsed
*
* @param useThreads true to use threads; false otherwise.
* @exception ExtendedIllegalStateException If a connection has already been made.
* @exception PropertyVetoException If any of the registered listeners vetos the property change.
**/
public void setThreadUsed(boolean useThreads) throws PropertyVetoException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting thread used:", useThreads);
if (propertiesFrozen_)
{
Trace.log(Trace.ERROR, "Cannot set thread used after connection has been made.");
throw new ExtendedIllegalStateException("threadUsed", ExtendedIllegalStateException.PROPERTY_NOT_CHANGED);
}
if (propertyChangeListeners_ == null && vetoableChangeListeners_ == null)
threadUsed_ = useThreads;
else
{
Boolean oldValue = Boolean.valueOf(threadUsed_);
Boolean newValue = Boolean.valueOf(useThreads);
if (vetoableChangeListeners_ != null)
vetoableChangeListeners_.fireVetoableChange("threadUsed", oldValue, newValue);
threadUsed_ = useThreads;
if (propertyChangeListeners_ != null)
propertyChangeListeners_.firePropertyChange("threadUsed", oldValue, newValue);
}
}
/**
* Sets the indicator for whether the default user is used. The default user is used if a system name is provided,
* but a user ID is not. If a default user is set for that system, then the default user is used.
*
* @param useDefaultUser The value indicating if the default user should be used. Set to true if default user should
* be used; false otherwise. The default is true, indicating that the default user is used.
* @exception PropertyVetoException If any of the registered listeners vetos the property change.
**/
public void setUseDefaultUser(boolean useDefaultUser) throws PropertyVetoException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting use default user:", useDefaultUser);
if (propertyChangeListeners_ == null && vetoableChangeListeners_ == null)
useDefaultUser_ = useDefaultUser;
else
{
Boolean oldValue = Boolean.valueOf(useDefaultUser_);
Boolean newValue = Boolean.valueOf(useDefaultUser);
if (vetoableChangeListeners_ != null)
vetoableChangeListeners_.fireVetoableChange("useDefaultUser", oldValue, newValue);
useDefaultUser_ = useDefaultUser;
if (propertyChangeListeners_ != null)
propertyChangeListeners_.firePropertyChange("useDefaultUser", oldValue, newValue);
}
}
/**
* Sets the indicator for whether the password cache is used. If password cache is used, then the user would only
* have to enter password once within a Java virtual machine. The default is to use the cache.
* Unless the application is running in its own private JVM, users are advised to turn off password caching, in
* order to ensure that another application within the same JVM cannot create a connection using the cached
* password.
*
* @param usePasswordCache The value indicating whether the password cache should be used. Set to true to use the
* password cache; false otherwise.
* @exception PropertyVetoException If any of the registered listeners vetos the property change.
**/
public void setUsePasswordCache(boolean usePasswordCache) throws PropertyVetoException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting use password cache:", usePasswordCache);
if (propertyChangeListeners_ == null && vetoableChangeListeners_ == null)
usePasswordCache_ = usePasswordCache;
else
{
Boolean oldValue = Boolean.valueOf(usePasswordCache_);
Boolean newValue = Boolean.valueOf(usePasswordCache);
if (vetoableChangeListeners_ != null)
vetoableChangeListeners_.fireVetoableChange("usePasswordCache", oldValue, newValue);
usePasswordCache_ = usePasswordCache;
if (propertyChangeListeners_ != null)
propertyChangeListeners_.firePropertyChange("usePasswordCache", oldValue, newValue);
}
}
/**
* Sets the user ID for this object. The user ID cannot be changed once a connection to the system has been
* established. If this method is used in conjunction with a Kerberos ticket, profile token, or identity token, the
* user profile associated with the authentication token must match this user ID.
*
* @param userId The user profile name.
* @exception ExtendedIllegalArgumentException If userId length is not valid.
* @exception ExtendedIllegalStateException If a connection has already been made.
* @exception PropertyVetoException If any of the registered listeners vetos the property change.
**/
public void setUserId(String userId) throws PropertyVetoException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting user ID: '" + userId + "'");
if (userId == null)
throw new NullPointerException("userId");
if (userId.equals(userId_)) return;
if (userId.length() > 10)
throw new ExtendedIllegalArgumentException("userId (" + userId + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
if (signonInfo_ != null)
{
Trace.log(Trace.ERROR, "Cannot set user ID after connection has been made.");
throw new ExtendedIllegalStateException("userId", ExtendedIllegalStateException.PROPERTY_NOT_CHANGED);
}
if (isTurkish()) {
userId = userId.toUpperCase(Locale.ENGLISH);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "This system locale is Turkish, userId.toUpperCase(Locale.ENGLISH)");
}
if (propertyChangeListeners_ == null && vetoableChangeListeners_ == null)
userId_ = userId.toUpperCase();
else
{
String oldValue = userId_;
String newValue = userId.toUpperCase();
if (vetoableChangeListeners_ != null)
vetoableChangeListeners_.fireVetoableChange("userId", oldValue, newValue);
userId_ = newValue;
if (propertyChangeListeners_ != null)
propertyChangeListeners_.firePropertyChange("userId", oldValue, newValue);
}
}
// Initiate sign-on to the system. This method is synchronized to prevent more than one thread from needlessly signing-on.
// This method can safely be called multiple times because it checks for a previous sign-on before performing the sign-on code.
synchronized void signon(boolean keepConnection) throws AS400SecurityException, IOException
{
// If we haven't already signed on.
if (signonInfo_ == null)
{
chooseImpl();
userId_ = resolveUserId(userId_, credVault_.getType(), mustUseSuppliedProfile_);
// If system name is set.
if (systemName_.length() != 0)
{
// If user ID is not set and we can use the default user.
if (userId_.length() == 0 && useDefaultUser_)
{
// Get the default user ID.
String defaultUserId = getDefaultUser(systemName_);
// If we have a default user ID for this system, set the user ID to it.
if (defaultUserId != null) userId_ = defaultUserId;
}
// If the user ID is set and the password is not set and we can use the password cache.
if (userId_.length() != 0 && credVault_.isEmpty() && usePasswordCache_)
{
// Get password from password cache.
synchronized (AS400.systemList)
{
for (int i = AS400.systemList.size() - 1; i >= 0; i--)
{
Object[] secobj = (Object[])AS400.systemList.elementAt(i);
if (systemName_.equalsIgnoreCase((String)secobj[0]) && userId_.equals(secobj[1]))
{
// We are taking an entry from the password cache
// and using it for our own AS400 object.
// Thus we must take a copy of it, to maintain
// the protocol of never using a credential vault
// that someone else has a reference to.
// Note that we do not need to bother emptying
// our existing vault; the if-check above has
// assured us that our vault is currently empty.
credVault_ = (CredentialVault)((CredentialVault)secobj[2]).clone();
}
}
}
}
}
try
{
// If the system name is set, we're not using proxy, and the password is not set, and the user has not told us not to.
if (systemName_.length() != 0 && proxyServer_.length() == 0 && credVault_.isEmpty()
&& (credVault_.getType() == AUTHENTICATION_SCHEME_GSS_TOKEN || gssOption_ != AS400.GSS_OPTION_NONE))
{
// Try for Kerberos.
byte[] newBytes = (gssCredential_ == null) ? TokenManager.getGSSToken(systemName_, gssName_) :
TokenManager2.getGSSToken(systemName_, gssCredential_);
// We do not have to empty the existing vault because the
// previous if-check assures us it is already empty.
credVault_ = new GSSTokenVault(newBytes);
}
}
catch (Throwable e)
{
if (credVault_.getType() == AUTHENTICATION_SCHEME_GSS_TOKEN || gssOption_ == AS400.GSS_OPTION_MANDATORY)
{
Trace.log(Trace.ERROR, "Error retrieving GSSToken:", e);
throw new AS400SecurityException(AS400SecurityException.KERBEROS_TICKET_NOT_VALID_RETRIEVE,e);
}
else
{ // Tolerate the exception - we don't require GSS.
Trace.log(Trace.DIAGNOSTIC, "GSSToken is not available:", e.getMessage());
Trace.log(Trace.DIAGNOSTIC, "Tolerated exception retrieving GSSToken:", e);
}
}
// Note: A user-supplied sign-on handler isn't necessarily GUI-based.
promptSignon();
if (!keepConnection) {
if (impl_.isConnected(AS400.SIGNON)) {
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Disconnecting temporary connection for validating signon.");
impl_.disconnect(AS400.SIGNON);
}
}
}
}
/**
* Returns the text representation of this AS400 object.
*
* @return The string representing this AS400 object.
**/
public String toString() {
return "AS400 (system name: '" + systemName_ + "' user ID: '" + userId_ + "'):" + super.toString();
}
// Determine if user ID matches current user ID.
private static boolean userIdMatchesLocal(String userId, boolean mustUseSuppliedProfile)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Determining if specified userID ("+userId+") matches current userID.");
boolean result;
// First, see if we are running on IBM i.
if (AS400.onAS400 && !mustUseSuppliedProfile && currentUserAvailable())
{
String currentUserID = CurrentUser.getUserID(AS400.nativeVRM.getVersionReleaseModification());
if (currentUserID == null)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Current userID information not available.");
result = false;
}
else
{
result = userId.equals(currentUserID);
if (Trace.traceOn_ && !result)
Trace.log(Trace.DIAGNOSTIC, "Specified userID ("+userId+") does not match current userID ("+currentUserID+").");
}
}
else
{
result = false;
if (Trace.traceOn_)
{
if (!AS400.onAS400) Trace.log(Trace.DIAGNOSTIC, "Not running on IBM i.");
if (mustUseSuppliedProfile) Trace.log(Trace.DIAGNOSTIC, "Caller specified must use supplied profile.");
if (!currentUserAvailable()) Trace.log(Trace.DIAGNOSTIC, "Class CurrentUser is not available.");
}
}
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Determined that specified userID ("+userId+") " + (result ? "matches" : "does not match") + " current userID.");
return result;
}
/**
* Validates the user ID and password on the system but does not add to the signed-on list. This means that a new
* AS400 object instance is created to do the validation. The user ID and system name need to be set before calling
* this method.
*
* Note: This will return true if the information is successfully validated. An unsuccessful validation will
* cause an exception to be thrown, false is never returned.
*
* Note:If an additional authentication factor has been set in the AS400 object, it is used.
*
* @return true if successful.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception ExtendedIllegalStateException If system name or user ID is not set.
* @exception IOException If an error occurs while communicating with the system.
**/
public boolean validateSignon() throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Validating Signon, no parameters.");
if (systemName_.length() == 0 && !systemNameLocal_)
{
Trace.log(Trace.ERROR, "Cannot validate signon before system name is set.");
throw new ExtendedIllegalStateException("systemName", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
userId_ = resolveUserId(userId_);
if (userId_.length() == 0)
{
Trace.log(Trace.ERROR, "Cannot validate signon before user ID is set.");
throw new ExtendedIllegalStateException("userId", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
return validateSignon(true, userId_, credVault_, additionalAuthenticationFactor_);
}
/**
* Validates the user ID and password on the system but does not add to the signed-on list. This means that a new
* AS400 object instance is created to do the validation. The user ID and system name need to be set before calling
* this method.
*
* Note: This will return true if the information is successfully validated. An unsuccessful validation will
* cause an exception to be thrown, false is never returned.
*
* Note:If an additional authentication factor has been set in the AS400 object, it is used.
*
* @param password The user profile password to validate.
* @return true if successful.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
* @deprecated
**/
@Deprecated
public boolean validateSignon(String password) throws AS400SecurityException, IOException
{
char[] passwordChars = (password == null) ? null : password.toCharArray();
try {
return validateSignon(passwordChars);
}
finally {
PasswordVault.clearArray(passwordChars);
}
}
/**
* Validates the user ID and password on the system but does not add to the signed-on list. This means that a new
* AS400 object instance is created to do the validation. The user ID and system name need to be set before calling
* this method.
*
* Note: This will return true if the information is successfully validated. An unsuccessful validation will
* cause an exception to be thrown, false is never returned.
*
* Note:If an additional authentication factor has been set in the AS400 object, it is used.
*
* @param password The user profile password to validate.
* @return true if successful.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception ExtendedIllegalStateException If system name or user ID is not set.
* @exception IOException If an error occurs while communicating with the system.
**/
public boolean validateSignon(char[] password) throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Validating Signon, with password.");
checkPasswordNullAndLength(password, "password");
if (systemName_.length() == 0 && !systemNameLocal_)
{
Trace.log(Trace.ERROR, "Cannot validate signon before system name is set.");
throw new ExtendedIllegalStateException("systemName", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
userId_ = resolveUserId(userId_);
if (userId_.length() == 0)
{
Trace.log(Trace.ERROR, "Cannot validate signon before user ID is set.");
throw new ExtendedIllegalStateException("userId", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
PasswordVault tempVault = new PasswordVault(password);
return validateSignon(true, userId_, tempVault, additionalAuthenticationFactor_);
}
/**
* Validates the user ID and password on the system but does not add to the signed-on list. This means that a new
* AS400 object instance is created to do the validation. The system name needs to be set prior to calling this
* method.
*
* Note: This will return true if the information is successfully validated. An unsuccessful validation will
* cause an exception to be thrown, false is never returned.
*
* Note:If an additional authentication factor has been set in the AS400 object, it is not used. If you want
* to use an additional authentication factor, see {@link #validateSignon(String, char[], char[])}
*
* @param userId The user profile name to validate.
* @param password The user profile password to validate.
* @return true if successful.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
* @deprecated Using a string as a password is insecure
**/
@Deprecated
public boolean validateSignon(String userId, String password) throws AS400SecurityException, IOException
{
char[] passwordChars = (password == null) ? null : password.toCharArray();
try {
return validateSignon(userId, passwordChars, null);
}
finally {
PasswordVault.clearArray(passwordChars);
}
}
/**
* Validates the user ID and password on the system but does not add to the signed-on list. This means that a new
* AS400 object instance is created to do the validation. The system name needs to be set prior to calling this
* method.
*
* Note: This will return true if the information is successfully validated. An unsuccessful validation will
* cause an exception to be thrown, false is never returned.
*
* Note:If an additional authentication factor has been set in the AS400 object, it is not used. If you want
* to use an additional authentication factor, see {@link #validateSignon(String, char[], char[])}
*
* @param userId The user profile name to validate.
* @param password The user profile password to validate.
* @return true if successful.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception IOException If an error occurs while communicating with the system.
**/
public boolean validateSignon(String userId, char[] password) throws AS400SecurityException, IOException
{
return validateSignon(userId, password, null);
}
/**
* Validates the user ID and password on the system but does not add to the signed-on list. This means that a new
* AS400 object instance is created to do the validation. The system name needs to be set prior to calling this
* method.
*
* Note: This will return true if the information is successfully validated. An unsuccessful validation will
* cause an exception to be thrown, false is never returned.
*
* @param userId The user profile name to validate.
* @param password The user profile password to validate.
* @param additionalAuthFactor Additional authentication factor (or null if not providing one).
* @return true if successful.
* @exception AS400SecurityException If a security or authority error occurs.
* @exception ExtendedIllegalArgumentException If userId or additionalAuthFactor length is not valid.
* @exception ExtendedIllegalStateException If system name or is not set.
* @exception IOException If an error occurs while communicating with the system.
**/
public boolean validateSignon(String userId, char[] password, char[] additionalAuthFactor) throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Validating signon, password and additional factor, user ID: '" + userId + "'");
if (userId == null)
throw new NullPointerException("userId");
if (userId.length() > 10)
throw new ExtendedIllegalArgumentException("userId (" + userId + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
if (additionalAuthFactor != null && additionalAuthFactor.length > ProfileTokenCredential.MAX_ADDITIONALAUTHENTICATIONFACTOR_LENGTH)
throw new ExtendedIllegalArgumentException("additionalAuthFactor", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
checkPasswordNullAndLength(password, "password");
if (systemName_.length() == 0 && !systemNameLocal_)
{
Trace.log(Trace.ERROR, "Cannot validate signon before system name is set.");
throw new ExtendedIllegalStateException("systemName", ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
PasswordVault tempVault = new PasswordVault(password);
if (isTurkish()) {
userId = userId.toUpperCase(Locale.ENGLISH);
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "This system locale is Turkish, userId.toUpperCase(Locale.ENGLISH)");
}
return validateSignon(true, userId.toUpperCase(), tempVault, additionalAuthFactor);
}
// Internal version of validate sign-on; takes checked user ID and twiddled password bytes.
// If the signon info is not valid, an exception is thrown.
private boolean validateSignon(boolean useNewInstance, String userId, CredentialVault pwVault, char[] additionalAuthFactor) throws AS400SecurityException, IOException
{
// Use a new instance when system, userid, and credentials are not part of this
// instance of AS400 class; otherwise, use this instance.
if (useNewInstance)
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Creating temporary connection for validating signon info.");
try (AS400 validationSystem = new AS400(systemName_, userId, pwVault, additionalAuthFactor))
{
validationSystem.proxyServer_ = proxyServer_;
// proxyClientConnection_ is not needed.
validationSystem.guiAvailable_ = false;
validationSystem.usePasswordCache_ = false;
validationSystem.useDefaultUser_ = false;
// showCheckboxes_ is not needed.
validationSystem.useSSLConnection_ = useSSLConnection_;
validationSystem.mustUseSockets_ = true; // force the use of the Signon Server
validationSystem.mustUseNetSockets_ = mustUseNetSockets_;
validationSystem.mustUseSuppliedProfile_ = mustUseSuppliedProfile_;
// threadUsed_ is not needed.
// locale_ in not needed.
// nlv_ in not needed.
validationSystem.socketProperties_.copyValues(socketProperties_);
if (validateSignonTimeOut_ > 0)
validationSystem.socketProperties_.setSoTimeout(validateSignonTimeOut_);
// ccsid_ is not needed.
// connectionListeners_ is not needed.
// dispatcher_ is not needed.
// propertyChangeListeners_ is not needed.
// vetoableChangeListeners_ is not needed.
// propertiesFrozen_ is not needed.
// impl_ is not copied.
// signonInfo_ is not copied.
validationSystem.signon(false); // signon(false) calls disconnect() when done
}
}
else
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Using AS400 object for validating signon.");
signon(false);
}
return true;
}
private void checkPasswordNullAndLength(char[] password, String label)
{
if (password == null)
throw new NullPointerException(label);
if (password.length > 128)
throw new ExtendedIllegalArgumentException(label+".length {" + password.length + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
}
/**
This tells AS400 to force prompt by displaying login dialog (actually the sign-on handler) prior to even trying to authenticate.
This is useful in cases where an application sends in incorrect dummy id/password and expects Toolbox to display the logon dialog.
In JDBC, we do some pre-validation of id/password. So JDBC may flag the id/password as invalid and then need
to let AS400 know that it just needs to display the logon dialog.
**/
void forcePrompt()
{
forcePrompt_ = true;
}
private int bidiStringType = BidiStringType.DEFAULT;
/**
* Sets bidi string type of the connection. See BidiStringType for more
* information and valid values.
*
* @param bidiStringType bidi string type to use for the connection.
*/
public void setBidiStringType(int bidiStringType){
this.bidiStringType = bidiStringType;
}
/**
* Returns bidi string type of the connection. See BidiStringType for more
* information and valid values.
*
* @return The bidi string type of the connection.
*/
public int getBidiStringType(){
return bidiStringType;
}
/**
* Determines whether Bidi processing should occur in AS400Text.toBytes() method
*/
public boolean bidiAS400Text = false;
/**
* Determines whether Bidi processing should occur in AS400Varchar.toBytes() method
*/
public boolean bidiAS400Varchar = false;
// Set the signon information for the connection
// Typicially used when the signon server has been skipped and the information
// is retrieved from a different host server
void setSignonInfo(int serverCCSID, int serverVersion, String userId)
{
if (signonInfo_ == null)
signonInfo_ = new SignonInfo();
signonInfo_.serverCCSID = serverCCSID;
signonInfo_.version = new ServerVersion(serverVersion);
signonInfo_.userId = userId;
ccsid_ = signonInfo_.serverCCSID;
}
/**
* Return whether default locale is Turkish.
*
* @return true if Turkish; otherwise, false.
*/
public static boolean isTurkish()
{
Locale defaultLocale = Locale.getDefault();
Locale Turkishlocale = new Locale("tr", "TR", "");
return (defaultLocale.equals(Turkishlocale) ) ? true : false;
}
/**
* Returns the timeout value when attempting to validate the sign on information.
*
* @return The timeout value in milliseconds.
*/
public int getvalidateSignonTimeOut() {
return validateSignonTimeOut_;
}
/**
* Set the the timeout value when when attempting to validate the sign on information.
*
* @param validateSignonTimeOut The timeout value in milliseconds.
*/
public void setvalidateSignonTimeOut(int validateSignonTimeOut) {
validateSignonTimeOut_ = validateSignonTimeOut;
}
/**
* Password level
*
* @return -1 - Not remote method, such as proxy method. 0, 1 - password type is DES 2, 3 - password type is SHA-1 4
* - password type is SHA-512
* @throws AS400SecurityException If a security or authority error occurs.
* @throws IOException If an error occurs while communicating with the system.
*/
public int passwordLevel() throws AS400SecurityException, IOException
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Checking if use password phrase");
chooseImpl();
signon(false);
int pwdlvl = -1;
if (impl_ instanceof AS400ImplRemote)
pwdlvl = ((AS400ImplRemote)impl_).getPasswordLevel();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Use password level: " + pwdlvl);
return pwdlvl;
}
/**
* This method is functionally equivalent to the resetAllServices() method.
*
* @see #resetAllServices
**/
@Override
public void close() {
// resetAllServices() ensures that HOSTCNN is disconnected from this AS400.
// disconnectAllServices() does not disconnect HOSTCNN connection.
resetAllServices();
}
// Method to ensure operations for secure AS400 instances are enforced.
private void ensureSecureInstance()
{
if (!isSecure())
{
Trace.log(Trace.ERROR, "Cannot perform opertation on non-secure AS400 object. ");
throw new ExtendedIllegalStateException(ExtendedIllegalStateException.IMPLEMENTATION_NOT_FOUND);
}
}
// Called during garbage collections - Cleans up all connections and daemon threads
@Override
protected void finalize() throws Throwable
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Finalize method for AS400 invoked.");
resetAllServices();
}
/**
* Returns true if host server communications is performed over a secure channel.
*
* Note:This method is the only reliable way to determine whether
* host server communications is performed over a secure channel.
* An AS400 object that is not an instance of SecureAS400 class can use
* secure communications in some instances.
*
* @return true if communications is done over secure channel; otherwise false.
**/
public boolean isSecure() {
return ((useSSLConnection_ != null) || (this instanceof SecureAS400));
}
// ======== START =================
// Following chunk of code moved from SecureAS400
// ======== START =================
/**
* Returns the key ring class name used for SSL communications with the system. The class
* com.ibm.as400.access.KeyRing is the default and will be returned if not overridden.
*
* Note:An exception will be thrown if the AS400 object is not an instance of SecureAS400.
*
* @return The key ring class name.
* @deprecated
**/
@Deprecated
public String getKeyRingName()
{
ensureSecureInstance();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting key ring name: null" );
return null;
}
/**
* Returns the proxy encryption mode. The proxy encryption mode specifies which portions of the communications
* between the client, proxy server, and IBM i system are encrypted.
*
* Note:An exception will be thrown if the AS400 object is not an instance of SecureAS400.
*
* @return The proxy encryption mode.
**/
public int getProxyEncryptionMode()
{
ensureSecureInstance();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Getting proxy encryption mode:", useSSLConnection_.proxyEncryptionMode_);
return useSSLConnection_.proxyEncryptionMode_;
}
/**
* Sets the key ring class name used for SSL communications with the system. This method is no longer supported
* because sslight is not longer supported.
*
* Note:An exception will be thrown if the AS400 object is not an instance of SecureAS400.
*
* @param keyRingName The key ring class name.
* @exception ExtendedIllegalStateException If object is not a secure instance.
* @exception PropertyVetoException If any of the registered listeners vetos the property change.
**/
public void setKeyRingName(String keyRingName) throws PropertyVetoException
{
ensureSecureInstance();
Trace.log(Trace.ERROR, "Cannot set key ring class name -- no sslight support ");
throw new ExtendedIllegalStateException("keyRingName", ExtendedIllegalStateException.IMPLEMENTATION_NOT_FOUND);
}
/**
* Sets the key ring class name used for SSL communications with the system. This method is no longer available since
* support for sslight has been removed.
*
* Note:An exception will be thrown if the AS400 object is not an instance of SecureAS400.
*
* @param keyRingName The key ring class name.
* @param keyRingPassword The password for the key ring class.
* @exception ExtendedIllegalStateException If object is not a secure instance.
* @exception PropertyVetoException If any of the registered listeners vetos the property change.
**/
public void setKeyRingName(String keyRingName, String keyRingPassword) throws PropertyVetoException
{
ensureSecureInstance();
Trace.log(Trace.ERROR, "Cannot set key ring class name -- no sslight support ");
throw new ExtendedIllegalStateException("keyRingName", ExtendedIllegalStateException.IMPLEMENTATION_NOT_FOUND);
}
/**
* Sets the key ring password used for SSL communications with the system.
*
* Note:An exception will be thrown if the AS400 object is not an instance of SecureAS400.
*
* @param keyRingPassword The password for the key ring class.
* @exception ExtendedIllegalStateException If object is not a secure instance.
* @deprecated
**/
@Deprecated
public void setKeyRingPassword(String keyRingPassword)
{
ensureSecureInstance();
Trace.log(Trace.ERROR, "Cannot set key ring class password.");
throw new ExtendedIllegalStateException("keyRingPassword", ExtendedIllegalStateException.PROPERTY_NOT_CHANGED);
}
/**
* Sets the proxy encryption mode. The proxy encryption mode specifies which portions of the communications between
* the client, proxy server, and IBM i system are encrypted. The default is to encrypt all communications. This value
* is ignored if a proxy server is not used.
* Valid proxy encryption modes are:
* {@link #CLIENT_TO_PROXY_SERVER CLIENT_TO_PROXY_SERVER} - encrypt between client and proxy server.
* {@link #PROXY_SERVER_TO_SERVER PROXY_SERVER_TO_SERVER} - encrypt between proxy server and IBM i system.
* {@link #CLIENT_TO_SERVER CLIENT_TO_SERVER} - encrypt both portions of connection.
*
* Note:An exception will be thrown if the AS400 object is not an instance of SecureAS400.
*
* @param proxyEncryptionMode The proxy encryption mode.
*
* @exception ExtendedIllegalArgumentException If proxyEncryptionMode value is not valid.
* @exception ExtendedIllegalStateException If object is not a secure instance.
* @exception PropertyVetoException If any of the registered listeners vetos the property change.
**/
public void setProxyEncryptionMode(int proxyEncryptionMode) throws PropertyVetoException
{
ensureSecureInstance();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Setting proxy encryption mode:", proxyEncryptionMode);
// Validate parameter.
if (proxyEncryptionMode < CLIENT_TO_PROXY_SERVER ||
proxyEncryptionMode > CLIENT_TO_SERVER)
{
Trace.log(Trace.ERROR, "Value of parameter 'proxyEncryptionMode' is not valid:", proxyEncryptionMode);
throw new ExtendedIllegalArgumentException("proxyEncryptionMode (" + proxyEncryptionMode + ")", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID);
}
if (propertiesFrozen_)
{
Trace.log(Trace.ERROR, "Cannot set proxy encryption mode after connection has been made.");
throw new ExtendedIllegalStateException("proxyEncryptionMode", ExtendedIllegalStateException.PROPERTY_NOT_CHANGED);
}
Integer oldValue = Integer.valueOf(useSSLConnection_.proxyEncryptionMode_);
Integer newValue = Integer.valueOf(proxyEncryptionMode);
if (vetoableChangeListeners_ != null)
vetoableChangeListeners_.fireVetoableChange("proxyEncryptionMode", oldValue, newValue);
useSSLConnection_.proxyEncryptionMode_ = proxyEncryptionMode;
if (propertyChangeListeners_ != null)
propertyChangeListeners_.firePropertyChange("proxyEncryptionMode", oldValue, newValue);
}
/**
* Set list of cipher suites.
*
* Note:An exception will be thrown if the AS400 object is not an instance of SecureAS400.
*
* @param suites Array of cipher suites.
*
* @exception ExtendedIllegalStateException If object is not a secure instance.
**/
public void setEnabledCipherSuites(String[] suites)
{
ensureSecureInstance();
if (suites != null && suites.length > 0)
{
changeCipherSuites = true;
newCipherSuites = suites;
}
}
// ======== END =================
// Previous chunk of code moved from SecureAS400
// ======== END =================
}