SessionUtils.java
/*
** Module : SessionUtils.java
** Abstract : Defines APIs used to access the SESSION attributes and methods.
**
** Copyright (c) 2013-2025, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------------Description---------------------------------------
** 001 CA 20130112 Created initial version.
** 002 CS 20130214 Added support for SESSION: EXPORT, SERVER-OPERATING-MODE, REMOTE attributes.
** 003 CA 20130221 getType was renamed to getResourceType.
** 004 CA 20130222 Added stubs for more SESSION-related attributes and methods: REMOTE,
** PARAMETER. The implementations for EXPORT, SERVER-OPERATING-MODE and REMOVE
** attrs call their ServerImpl counterparts.
** 005 OM 20130304 Refactored isValid and isUnknown of WrappedResource to valid and unknown.
** 006 CA 20130529 Added implementations for FIRST-SERVER, LAST-SERVER, REMOTE, EXPORT and
** SERVER-OPERATING-MODE.
** 007 OM 20130510 Added support for date-related SESSION attributes so they can be queried from
** client side.
** 008 CA 20130822 Allow access to the DATE-FORMAT attribute (set/getDateOrder) outside of a P2J
** server.
** 009 CA 20130927 Static proxies need the unknown() API. Resource type is determined from
** LegacyResource constants. Implemented the following attributes: FIRST-BUFFER,
** FIRST-QUERY, FIRST-/LAST-SOCKET, FIRST-/LAST-SERVER-SOCKET.
** 010 CA 20131002 Implemented the PARAMETER attribute.
** 011 CA 20140701 Added PIXELS-PER-ROW and PIXELS-PER-COLUMN.
** 012 CA 20140702 Implemented PIXELS-PER-ROW and PIXELS-PER-COLUMN.
** 013 OM 20141110 Refactored get/setDateOrder() to get/setDateFormat().
** 014 EVL 20141216 Adding SESSION:TOOLTIPS attribute handling, server side part.
** 015 GES 20141228 Completed PARAMETER attribute implementation by storing it in a context-local
** and allowing the client command line/bootstrap to override any default value
** found in the directory.
** 016 GES 20150227 Added FIRST-CHILD and LAST-CHILD attribute support.
** 017 HC 20150508 Improvements to GUI window scrolling support.
** 018 CA 20150502 The resource ID needs to be kept at the resource, so it can be accessed after
** the resource is deleted.
** 019 OM 20150915 Added stub for SESSION:DEBUG-ALERT, DATA-ENTRY-RETURN and APPL-ALERT-BOXES
** attributes and method. Fixed set3D method. Added LOAD-ICON.
** 020 HC 20160222 Fixed error reporting when assigning session read-only attributes.
** 021 IAS 20160302 Support for the APPL-ALERT-BOXES, DATA-ENTRY-RETURN, DEBUG-ALERT and
** IMMEDIATE-DISPLAY SESSION attributes.
** 022 IAS 20160328 Client log support.
** 023 OM 20160401 Fixed method name collision for static proxy.
** 024 HC 20170811 Added conversion support for SESSION attributes PRINTER-NAME, PRINTER-PORT,
** PRINTER-CONTROL-HANDLE, PRINTER-HDC and the method GET-PRINTERS.
** HC 20170817 Added conversion support and runtime stubs for SESSION:STARTUP-PARAMETERS and
** SESSION:SUPPRESS-WARNINGS.
** 025 HC 20171003 Implemented SESSION:SUPPRESS-WARNINGS runtime support and the ability to
** handle (display or output depending on the runtime state) legacy warnings.
** 026 HC 20171024 Runtime support for SYSTEM-DIALOG PRINT-SETUP and OUTPUT TO PRINTER.
** 027 EVL 20180220 Now the current printer name is getting from client OS base.
** 028 CA 20180502 Fixed issues with time-related attributes used by SessionExports.
** 029 CA 20180503 Added MULTITASKING-INTERVAL, SYSTEM-ALERT-BOXES and SERVER-CONNECTION-ID.
** Renamed/moved some SESSION attribute getters/setters to fix issues with using
** the SESSION via a handle.
** 030 CA 20181213 Added SESSION:FIRST-OBJECT and LAST-OBJECT attributes (stubs).
** Added loadIcon(character).
** 031 CA 20190122 Implemented FIRST-OBJECT and LAST-OBJECT.
** 032 CA 20190416 Added LOCAL-VERSION-INFO and CURRENT-REQUEST-INFO stubs.
** OM 20190416 Added FIRST-DATASET and FIRST-DATA-SOURCE methods.
** 033 CA 20190423 Added these attributes: CURRENT-RESPONSE-INFO, ICFPARAMETER, CONTEXT-HELP-FILE,
** SERVER-CONNECTION-BOUND-REQUEST, stubs only.
** 034 EVL 20190513 Added I18nOps for SESSION CP attributes getters moved from EnvironmentOps.
** 035 CA 20190520 Fixed the name of some OO classes.
** 036 CA 20190628 Added SERVER-CONNECTION-BOUND and SERVER-CONNECTION-CONTEXT stubs.
** 037 CA 20190710 LOCAL-VERSION-INFO and LOCAL-REQUEST-INFO return proper instances.
** CA 20190717 Added ICFPARAMETER runtime support.
** 038 RFB 20200304 Added SESSION:EXIT-CODE handlers.
** 039 IAS 20200410 Reworked support of the date-related SESSION attributes.
** CA 20200427 Added support for SERVER-CONNECTION-BOUND, SERVER-CONNECTION-CONTEXT,
** CURRENT-REQUEST-INFO, CURRENT-RESPONSE-INFO, CONTEXT-HELP-FILE,
** SERVER-CONNECTION-BOUND-REQUEST.
** 040 OM 20201030 Invalid attribute API support for getters/setters.
** OM 20201203 Fixed handling of READ/ONLY attributes.
** CA 20210213 The requestInfo and responseInfo must be vars.
** OM 20210226 Added DATA-SOURCE sibling navigation support. Fixed Dataset handles order.
** CA 20210920 Send MULTITASKING-INTERVAL to the client-side (which has runtime support).
** CA 20220114 Added SESSION:CLIENT-DISCONNECTED and TERMINATION-HOOK FWD extension attributes.
** CA 20220128 TERMINATION-HOOK can not be set for remote sessions (appserver).
** CA 20220208 Added ERROR-STACK-TRACE and -errorstack runtime.
** VVT 20221003 CommonHandle.getResourceType() method renamed to resourceType() to prevent conflicts
** with namesakes in DMO. See #6694.
** CA 20220930 Cache the proxy associated with the SESSION system handle.
** EVL 20221007 Adding runtime support for SESSION:LOAD-ICON.
** CA 20220426 Added SUPPRESS-WARNINGS-LIST attribute stubs.
** VVT 20220913 CommonHandle.getResourceType() method renamed to resourceType() to prevent conflicts
** with namesakes in DMO. See #6694.
** CA 20221123 FIRST-/LAST-CHILD do not report anything for batch or appserver clients (as WINDOW widgets
** don't exist).
** 041 GBB 20230313 isClientLog param removed.
** 042 GBB 20230512 Logging methods replaced by CentralLogger/ConversionStatus.
** 043 GBB 20230628 Added SESSION-ID attribute.
** 044 GBB 20230719 Fix for SESSION-ID, moved to a separate interface.
** 045 TT 20230621 Added support for the StartupParameters.
** TT 20230628 Added the functionality for session:suppress-warnings-list.
** 046 TT 20230901 Moved StartupParameters into a ContextLocal container with isResetAllowed = false.
** 047 GBB 20230825 Adding support for AUTH-BLOB.
** 048 GBB 20231102 Added SESSION:RELATED-SESSION-ID.
** Added SESSION:NEW-SESSION(character, character).
** 049 GBB 20231204 Adding overloading methods for SESSION:NEW-SESSION.
** 050 GBB 20240214 Added DEVICE-ID.
** 051 GBB 20240301 Added multiple custom session attributes.
** 052 GBB 20240515 Added SESSION:GET-LOGIN-PARAMETER method.
** 053 GBB 20240529 getLoginParam() to accept 1-based index as in OE.
** 054 GBB 20240610 Adds conditions for unknown CURRENT-RESPONSE-INFO / CURRENT-REQUEST-INFO.
** 055 HC 20240630 Implemented support for WEB-FILE-UPLOAD statement.
** 056 GBB 20240709 Fixing getLoginParam javadoc.
** 057 GBB 20240826 Storing and retrieving SSO storageId.
** 058 GBB 20240912 Don't call the client with date updates if ALL OS resources are enabled server-side.
** 059 ICP 20250129 Used logical constant to leverage cached instances.
** 060 ES 20250321 Added getLastAsyncRequest and getFirstAsyncRequest method, for FIRST-ASYNC-REQUEST and
** LAST-ASYNC-REQUEST attributes.
** 061 GBB 20250403 AppServerManager method renamed to isMultiSession.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.util;
import com.goldencode.p2j.main.*;
import com.goldencode.p2j.net.*;
import com.goldencode.p2j.net.Session;
import com.goldencode.p2j.oo.lang.*;
import com.goldencode.p2j.security.*;
import com.goldencode.p2j.ui.*;
import com.goldencode.p2j.util.logging.*;
import com.goldencode.p2j.util.osresource.*;
import com.goldencode.proxy.*;
import java.util.*;
import java.util.stream.*;
/**
* This class provides implementation for SESSION attributes and methods.
* Mainly, the APIs implemented here are defined in the {@link CommonSession}
* interface (or one of its super interfaces) and are not statically
* implemented by the classes used by the {@link #asHandle()}.
*/
public class SessionUtils
{
/** Logger */
private static final CentralLogger LOG = CentralLogger.get(SessionUtils.class);
/** Context local proxy that allows SESSION attributes to be pushed from server to client. */
private static final ContextLocal<WorkArea> work = new ContextLocal<WorkArea>()
{
/**
* Initializes the work area, the first time it is requested within a
* new context.
* <p>
* This will obtain a unique instance of <code>SessionExports</code> depending on which
* side (server or client) it is called the returned value can be a local or a network
* proxy instance.
*
* @return The newly instantiated work area.
*/
@Override
protected WorkArea initialValue()
{
WorkArea wa = new WorkArea();
if (!ErrorManager.isHeadless() &&
!SessionManager.get().isLeaf() &&
!OSResourceManager.getInstance().isServerSide(OsResourceType.ALL))
{
wa.exports = (SessionExports) RemoteObject.obtainInstance(SessionExports.class, true);
}
return wa;
}
};
/** Lock for synchronizing device id writes. */
private static final Object DEVICE_ID_LOCK = new Object();
/** Context local proxy that allows the startup parameters to be pushed from server to client. */
private static final ContextLocal<StartupParameters> startupParameters = new ContextLocal<StartupParameters>()
{
/**
* Initializes the work area, the first time it is requested within a new context.
*
* @return The newly instantiated startup configuration.
*/
@Override
protected StartupParameters initialValue()
{
return new StartupParameters();
}
/**
* Check if this instance is allowed to be reset.
*
* @return <code>false</code> by default.
*/
@Override
protected boolean isResetAllowed()
{
return false;
}
};
/**
* Get a the instance for the SESSION system handle. Is obtained using
* a call to the {@link StaticProxy#obtain(Class, Class[])}, using the
* {@link CommonSession} interface and its methods implemented by these
* classes: {@link SessionUtils}, {@link EnvironmentOps}, {@link date},
* {@link LogicalTerminal}, {@link ProcedureManager}.
*
* @return See above.
*/
public static handle asHandle()
{
WorkArea wa = work.get();
if (wa.proxy != null)
{
return new handle(wa.proxy);
}
Class[] classes =
{
SessionUtils.class,
EnvironmentOps.class,
date.class,
I18nOps.class,
LogicalTerminal.class,
ProcedureManager.class,
NumberType.class
};
CommonSession proxy = StaticProxy.obtain(CommonSession.class, classes);
wa.proxy = proxy;
if (wa.id == null)
{
wa.id = handle.resourceId(proxy);
}
return new handle(proxy);
}
/**
* Returns the session unique identifier.
*
* @return The session unique identifier.
*/
public static character getSessionId()
{
WorkArea wa = work.get();
if (wa.sessionId == null)
{
wa.sessionId = UUID.randomUUID().toString();
}
return new character(wa.sessionId);
}
/**
* Set the SESSION-ID Attribute.
*
* @param sessionId
* The value of the SESSION-ID attribute.
*/
public static void setSessionId(character sessionId)
{
readOnlyError("SESSION-ID");
}
/**
* Set the SESSION-ID Attribute.
*
* @param sessionId
* The value of the SESSION-ID attribute.
*/
public static void setSessionId(String sessionId)
{
readOnlyError("SESSION-ID");
}
/**
* Returns the authentication blob content.
*
* @return The authentication blob content.
*/
public static character getAuthBlob()
{
return new character(work.get().authBlob);
}
/**
* Returns the device ID.
*
* @return The device ID.
*/
public static character getDeviceId()
{
return new character(work.get().deviceId);
}
/**
* Sets the authentication blob content.
*
* @param authBlob
* The authentication blob content.
*/
public static void setAuthBlob(String authBlob)
{
work.get().authBlob = authBlob;
}
/**
* Sets the device ID. It can be set only once in the lifespan of the session.
*
* @param deviceId
* The device ID.
*/
public static void setDeviceId(String deviceId)
{
synchronized(DEVICE_ID_LOCK)
{
if (work.get().deviceId != null)
{
LOG.info("Device ID can't be changed for the session.");
return;
}
work.get().deviceId = deviceId;
}
}
/**
* Returns the unique ID of the original session that was forked. Corresponds with the
* <code>SESSION:RELATED-SESSION-ID</code> system handle attribute.
*
* @return The unique ID of the original session that was forked.
*/
public static character getRelatedSessionId()
{
WorkArea wa = work.get();
if (wa.relatedSessionId == null)
{
wa.relatedSessionId = getSessionId().toStringMessage();
}
return new character(wa.relatedSessionId);
}
/**
* Sets the RELATED-SESSION-ID attribute. Setter can't be accessed in 4GL.
*
* @param relatedSessionId
* The unique ID of the original session that was forked.
*/
public static void setRelatedSessionId(String relatedSessionId)
{
work.get().relatedSessionId = relatedSessionId;
}
/**
* Starts a new forked session. Corresponds with the <code>SESSION:NEW-SESSION(character, character)
* </code> system handle method.
*
* @param cfgOverrides
* New session startup parameters.
* @param authBlob
* The value to be assigned to SESSION:AUTH-BLOB in the new session.
*/
public static void forkNewSession(character cfgOverrides, character authBlob)
{
String cfgOverridesString = cfgOverrides == null || cfgOverrides.isUnknown() ? null :
cfgOverrides.toStringMessage();
String authBlobString = authBlob == null || authBlob.isUnknown() ? null : authBlob.toStringMessage();
forkNewSession(cfgOverridesString, authBlobString);
}
/**
* Starts a new forked session. Corresponds with the <code>SESSION:NEW-SESSION(String, character)
* </code> system handle method.
*
* @param cfgOverrides
* New session startup parameters.
* @param authBlob
* The value to be assigned to SESSION:AUTH-BLOB in the new session.
*/
public static void forkNewSession(String cfgOverrides, character authBlob)
{
String authBlobString = authBlob == null || authBlob.isUnknown() ? null : authBlob.toStringMessage();
forkNewSession(cfgOverrides, authBlobString);
}
/**
* Starts a new forked session. Corresponds with the <code>SESSION:NEW-SESSION(character, String)
* </code> system handle method.
*
* @param cfgOverrides
* New session startup parameters.
* @param authBlob
* The value to be assigned to SESSION:AUTH-BLOB in the new session.
*/
public static void forkNewSession(character cfgOverrides, String authBlob)
{
String cfgOverridesString = cfgOverrides == null || cfgOverrides.isUnknown() ? null :
cfgOverrides.toStringMessage();
forkNewSession(cfgOverridesString, authBlob);
}
/**
* Starts a new forked session. Corresponds with the <code>SESSION:NEW-SESSION(String, String)
* </code> system handle method.
*
* @param cfgOverrides
* New session startup parameters.
* @param authBlob
* The value to be assigned to SESSION:AUTH-BLOB in the new session.
*/
public static void forkNewSession(String cfgOverrides, String authBlob)
{
if (!StandardServer.getClientParameters().web)
{
LOG.warning("Attempt to fork a new session for a non-web client failed.");
return;
}
SessionForkManager.getInstance().forkNewSession(cfgOverrides, authBlob);
}
/**
* Get this resource's ID.
*
* @return The resource's ID.
*/
public static Long id()
{
WorkArea wa = work.get();
return wa.id;
}
/**
* Set this resource's ID.
* <p>
* This is a no-op for system handles.
*
* @param id
* The resource's ID.
*/
public static void id(long id)
{
// no-op
}
/**
* Get the type of its associated handle.
*
* @return Always return the PSEUDO-WIDGET value.
*/
public static character resourceType()
{
return new character(LegacyResource.PSEUDO_WIDGET);
}
/**
* Implementation for the {@link WrappedResource#valid()} API.
*
* @return Always true.
*/
public static boolean valid()
{
return true;
}
/**
* Implementation for the {@link WrappedResource#unknown()} API.
*
* @return Always false.
*/
public static boolean unknown()
{
return false;
}
/**
* API needed to implement read-only attribute assignment (a 4GL "feature").
*
* @param attribute
* The attribute's name.
*
* @see handle#readOnlyError(handle, String)
*/
public static void readOnlyError(String attribute)
{
// the following attribute names are reported in their shortest forms
if (attribute.toUpperCase().startsWith("DISPLAY-TY"))
{
attribute = "DISPLAY-T";
}
else if (attribute.toUpperCase().startsWith("HEIGHT-C"))
{
attribute = "HEIGHT";
}
else if (attribute.toUpperCase().startsWith("WIDTH-C"))
{
attribute = "WIDTH";
}
// the error message for session read-only attributes is different from the one emitted by
// handle.readOnlyError() - settable is spelled with two 't' and there is no word 'widget' at the end of
// the message.
ErrorManager.recordOrShowError(4052, attribute.toUpperCase(), "settable", LegacyResource.PSEUDO_WIDGET);
}
/**
* Emitted and to be used only in cases the attribute is read-only. It displays appropriate error message.
* <br>
* TODO: decide whether the following message can be raised here:<br>
* {@code **Unable to assign UNKNOWN value to attribute <attribute> on <widget id>.}
*
* @param attribute
* The read-only attribute.
* @param expr
* The value which is attempted to be assigned to the read-only attribute.
*/
public static void readOnlyError(String attribute, Object expr)
{
readOnlyError(attribute);
}
/**
* Indicates if the session is for the context of an appserver.
*
* @return <code>true</code> if the session is for the context of an appserver.
*/
public static logical isRemote()
{
return new logical(_isRemote());
}
/**
* Indicates if the session is for the context of an appserver.
*
* @return <code>true</code> if the session is for the context of an appserver.
*/
public static boolean _isRemote()
{
return AppServerManager.isRemote();
}
/**
* Get the CLIENT-DISCONNECTED attribute of this session.
*
* @return <code>true</code> if the FWD client has disconnected (due to an abend, socket close, etc).
*/
public static logical isClientDisconnected()
{
if (work.get().clientDisconnected)
{
return new logical(true);
}
// check if the client socket is gone
Session session = SessionManager.get().getSession();
return new logical(!session.isRunning());
}
/**
* Get the TERMINATION-HOOK attribute of this session.
*
* @return See above.
*/
@LegacyAttribute(name = "TERMINATION-HOOK")
public static character getTerminationHook()
{
return new character(work.get().terminationHook);
}
/**
* Set the TERMINATION-HOOK attribute of this session.
* <p>
* This attribute is valid only for non-remote sessions - for a remote session, a message will be logged.
*
* @param hook
* The hook, a character expression with an external program name or a static method reference
* following the <code>com.goldencode.Foo:someStaticMethod</code> syntax.
*/
@LegacyAttribute(name = "TERMINATION-HOOK", setter = true)
public static void setTerminationHook(character hook)
{
if (_isRemote())
{
ErrorManager.recordOrShowError(-1001, "TERMINATION-HOOK can not be set for remote sessions.",
false, false);
return;
}
work.get().terminationHook = hook.isUnknown() ? null : hook.toStringMessage();
}
/**
* Set the TERMINATION-HOOK attribute of this session.
*
* @param hook
* The hook, a character expression with an external program name or a static method reference
* following the <code>com.goldencode.Foo:someStaticMethod</code> syntax.
*/
public static void setTerminationHook(String hook)
{
work.get().terminationHook = hook;
}
/**
* Method implementation for getting the SERVER-OPERATING-MODE attribute of the session handle.
* <p>
* Possible values:
* <ul>
* <li>State-reset
* <li>State-aware
* <li>Stateless
* <li>State-free
* </ul>
*
* @return The corresponding SERVER-OPERATING-MODE attribute of the session handle.
*/
public static character getServerOperatingMode()
{
return AppServerManager.getServerOperatingMode();
}
/**
* Method that specifies the remote procedures the client can execute from the AppServer
* session.
*
* @param procList
* The list of procedure and name-patterns separated by comma.
*
* @return <code>true</code> if the method succeeded.
*/
public static logical export(String procList)
{
return AppServerManager.export(procList);
}
/**
* Method that specifies the remote procedures the client can execute from the AppServer
* session.
*
* @param procList
* The list of procedure and name-patterns separated by comma.
*
* @return <code>true</code> if the method succeeded.
*/
public static logical export(character procList)
{
return AppServerManager.export(procList);
}
/**
* Get the value of the PARAMETER attribute, which is set to the value of the 4GL
* <code>-param</code> command line option specified for the current session.
* <p>
* The following is the precedence order (highest to lowest) for obtaining the
* value of this parameter:
* <p>
* <ul>
* <li> The client command line.
* <li> The client bootstrap configuration.
* <li> The directory using relative lookup and the "startup_parameter" node.
* </ul>
*
* @return The <code>SESSION:PARAMETER</code> value for this context.
*/
public static character getParameter()
{
return new character(startupParameters.get().getParameter());
}
/**
* Returns the handle for the first dynamic buffer in the first table containing a dynamic
* buffer.
*
* @return See above.
*/
public static handle firstBuffer()
{
// TODO: this should be OK, but more testing is needed to check if 4GL doesn't sort them in
// a different order (i.e. using the table name)
return HandleChain.firstResource(LegacyResource.BUFFER);
}
/**
* Returns the handle for the first window in the session.
*
* @return The first window in the session's list of windows.
*/
public static handle firstChild()
{
if (EnvironmentOps.isBatchMode().booleanValue() || AppServerManager.isRemote())
{
return new handle();
}
return HandleChain.firstResource(LegacyResource.WINDOW);
}
/**
* Returns the handle for the last window in the session.
*
* @return The last window in the session's list of windows.
*/
public static handle lastChild()
{
if (EnvironmentOps.isBatchMode().booleanValue() || AppServerManager.isRemote())
{
return new handle();
}
return HandleChain.lastResource(LegacyResource.WINDOW);
}
/**
* Returns the handle for the first created dynamic query.
* <p>
* TODO: this should call a worker method from the persist package.
*
* @return See above.
*/
public static handle firstQuery()
{
return HandleChain.firstResource(LegacyResource.QUERY);
}
/**
* Get the FIRST-SERVER attribute of this session.
*
* @return See above.
*/
public static handle firstServer()
{
return HandleChain.firstResource(LegacyResource.SERVER);
}
/**
* Get the FIRST-SERVER-SOCKET attribute of this session.
*
* @return See above.
*/
public static handle firstServerSocket()
{
return HandleChain.firstResource(LegacyResource.SERVER_SOCKET);
}
/**
* Get the FIRST-SOCKET attribute of this session.
*
* @return See above.
*/
public static handle firstSocket()
{
return HandleChain.firstResource(LegacyResource.SOCKET);
}
/**
* Get the LAST-SERVER attribute of this session.
*
* @return See above.
*/
public static handle lastServer()
{
return HandleChain.lastResource(LegacyResource.SERVER);
}
/**
* Get the LAST-SERVER-SOCKET attribute of this session.
*
* @return See above.
*/
public static handle lastServerSocket()
{
return HandleChain.lastResource(LegacyResource.SERVER_SOCKET);
}
/**
* Get the LAST-SOCKET attribute of this session.
*
* @return See above.
*/
public static handle lastSocket()
{
return HandleChain.lastResource(LegacyResource.SOCKET);
}
/**
* Obtain a handle to the first dynamic {@code DataSet} object created in the current session.
* <p>
* The list of Datasets is reversed (it is a stack instead of a queue).
*
* @return the value of {@code SESSION:FIRST-DATASET}, as described above.
*/
public static handle getFirstDataSet()
{
return HandleChain.lastResource(LegacyResource.DATASET);
}
/**
* Obtain a handle to the first dynamic {@code DataSource} object created in the current session.
* <p>
* The list of DataSources is reversed (it is a stack instead of a queue).
*
* @return the value of {@code SESSION:FIRST-DATA-SOURCE}, as described above.
*/
public static handle getFirstDataSource()
{
return HandleChain.lastResource(LegacyResource.DATA_SOURCE);
}
/**
* Sets the order of date components (SESSION:DATE-FORMAT) for conversion to/from strings.
* <p>
* The order of the 3 date sub-components as a 3 character string using "M", "D" and "Y" once
* each. The order from index 0 to index 2 represents the left to right ordering of the
* components. So the leftmost date component will be defined by the character at index
* position 0.
* <p>
* The value set is specific to the current user's context.
*
* @param dateFormat
* Defines the order of date components for conversion to/from strings.
*/
public static void setDateFormat(String dateFormat)
{
setDateFormat(new character(dateFormat));
}
/**
* Sets the order of date components (SESSION:DATE-FORMAT) for conversion to/from strings.
* <p>
* The order of the 3 date sub-components as a 3 character string using "M", "D" and "Y" once
* each. The order from index 0 to index 2 represents the left to right ordering of the
* components. So the leftmost date component will be defined by the character at index
* position 0.
* <p>
* The value set is specific to the current user's context.
*
* @param dateFormat
* Defines the order of date components for conversion to/from strings.
*/
public static void setDateFormat(character dateFormat)
{
SessionDateUtils.INSTANCE.setDateFormat(dateFormat);
WorkArea wa = work.get();
if (wa.exports != null)
{
wa.exports.setDateFormat(dateFormat);
}
}
/**
* Gets the order of date components (SESSION:DATE-FORMAT) for conversion to/from strings.
* <p>
* The order of the 3 date sub-components is a 3 character string using
* "M", "D" and "Y" once each. The order from index 0 to index 2
* represents the left to right ordering of the components. So the leftmost
* date component will be defined by the character at index position 0.
* <p>
* The value accessed is specific to the current user's context.
*
* @return Defines the order of date components for conversion to/from strings.
*/
public static character getDateFormat()
{
return SessionDateUtils.INSTANCE.getDateFormat();
}
/**
* Get the state of SESSION:DEBUG-ALERT attribute.
*
* @return the state of SESSION:DEBUG-ALERT attribute.
*/
public static logical isDebugAlert()
{
return new logical(work.get().isDebugAlert);
}
/**
* Set the state of SESSION:DEBUG-ALERT attribute.
*
* @param on
* The new state for SESSION:DEBUG-ALERT attribute.
*/
public static void setDebugAlert(logical on)
{
setDebugAlert(on == null || on.isUnknown() ? false : on.booleanValue());
}
/**
* Set the state of SESSION:DEBUG-ALERT attribute.
*
* @param on
* The new state for SESSION:DEBUG-ALERT attribute.
*/
public static void setDebugAlert(boolean on)
{
work.get().isDebugAlert = on;
}
/**
* Get the state of SESSION:DATA-ENTRY-RETURN attribute.
*
* @return the state of SESSION:DATA-ENTRY-RETURN attribute.
*/
public static logical isDataEntryReturn()
{
return LogicalTerminal._isDataEntryReturn();
}
/**
* Set the state of SESSION:DATA-ENTRY-RETURN attribute.
*
* @param on
* The new state for SESSION:DATA-ENTRY-RETURN attribute.
*/
public static void setDataEntryReturn(logical on)
{
if (on == null || on.isUnknown())
{
return;
}
setDataEntryReturn(on.booleanValue());
}
/**
* Set the state of SESSION:DATA-ENTRY-RETURN attribute.
*
* @param on
* The new state for SESSION:DATA-ENTRY-RETURN attribute.
*/
public static void setDataEntryReturn(boolean on)
{
LogicalTerminal.setDataEntryReturn(on);
}
/**
* Set the state of SESSION:LOAD-ICON attribute.
*
* @param iconName
* The file name of the icon to be loaded
* @return <code>true</code> if successful
*/
public static logical loadIcon(String iconName)
{
// simple parameter check
if (iconName == null || iconName.isEmpty())
{
return new logical(false);
}
return new logical(LogicalTerminal.setWindowDefaultIcon(iconName));
}
/**
* Set the state of SESSION:LOAD-ICON attribute.
*
* @param iconName
* The file name of the icon to be loaded
* @return <code>true</code> if successful
*/
public static logical loadIcon(character iconName)
{
// simple parameter check
return iconName == null || iconName.isUnknown() ? new logical(false) : loadIcon(iconName.getValue());
}
/**
* Sets the SESSION:TIMEZONE used as the default offset in minutes from
* UTC for this user's context.
*
* @param offset
* The new timezone offset which must be between -840 and 840
* inclusive. The value may also be <code>unknown</code> which
* is the equivalent of resetting this attribute to the default.
*/
public static void setSessionTimeZone(NumberType offset)
{
SessionDateUtils.INSTANCE.setSessionTimeZone(offset);
WorkArea wa = work.get();
if (wa.exports != null)
{
wa.exports.setSessionTimeZone(offset);
}
}
/**
* Accesses the SESSION:TIMEZONE used as the default offset in minutes from
* UTC for this user's context.
*
* @return The timezone offset. If this has never been set, then
* <code>unknown</code> will be returned.
*/
public static integer getSessionTimeZone()
{
return SessionDateUtils.INSTANCE.getSessionTimeZone();
}
/**
* Obtains the currently configured TIME-SOURCE attribute for the current
* user's context. This attribute is can be read and written but it is
* not honored for date/time processing in P2J. The intention of the
* attribute is to define the system from which time values will be obtained.
* In P2J, time values are always obtained from the application server.
* <p>
* The default value is "local" which in Progress means that the client
* machine is the source (this is the same as the empty string ""). It is
* common to use a database name in the 4GL, which makes the application
* use the database server as the time source.
*
* @return The time source attribute.
*/
public static character getSessionTimeSource()
{
return SessionDateUtils.INSTANCE.getSessionTimeSource();
}
/**
* Sets the <code>TIME-SOURCE</code> attribute for the user's context.
* This attribute is can be read and written but it is not honored for
* date/time processing in P2J. The intention of the attribute is to define
* the system from which time values will be obtained. In P2J, time values
* are always obtained from the application server.
*
* @param timeSource
* The new value to set. If <code>null</code>, then the empty
* string will be used, which in the 4GL has the same affect as
* "local".
*/
public static void setSessionTimeSource(character timeSource)
{
SessionDateUtils.INSTANCE.setSessionTimeSource(timeSource);
WorkArea wa = work.get();
if (wa.exports != null)
{
wa.exports.setSessionTimeSource(timeSource);
}
}
/**
* Obtains the currently configured DISPLAY-TIMEZONE attribute for the current
* user's context. This attribute is used for displaying DATETIME-TZ values that do not have
* the timezone specified in the display format.
*
* @return The display-timezone attribute.
*/
public static integer getSessionDisplayTimeZone()
{
return SessionDateUtils.INSTANCE.getSessionDisplayTimeZone();
}
/**
* Sets the <code>DISPLAY-TIMEZONE</code> attribute for the user's context.
* This attribute is used for displaying DATETIME-TZ values that do not have
* the timezone specified in the display format.
*
* @param displayTimezone
* The new value to set.
*/
public static void setSessionDisplayTimeZone(NumberType displayTimezone)
{
SessionDateUtils.INSTANCE.setSessionDisplayTimeZone(displayTimezone);
WorkArea wa = work.get();
if (wa.exports != null)
{
wa.exports.setSessionDisplayTimeZone(displayTimezone);
}
}
/**
* Implementation of SESSION:YEAR-OFFSET attribute getter. Returns the
* currently configured start year for the two-digit Y2K windowing range.
* This is the equivalent to the Progress -yy command line parameter. The
* default value is 1950 unless otherwise specified in the directory (see
* {@link date#getWindowingYear}).
*
* @return The start year for the two-digit windowing range.
*/
public static integer getYearOffset()
{
return SessionDateUtils.INSTANCE.getYearOffset();
}
/**
* Implementation of SESSION:YEAR-OFFSET attribute setter. Sets the
* configured start year for the two-digit Y2K windowing range. This is
* the equivalent of the Progress -yy command line parameter. The
* default value is 1950 unless otherwise specified in the directory (see
* {@link date#getWindowingYear}).
*
* @param year
* The new start year for the two-digit windowing range.
*/
public static void setYearOffset(NumberType year)
{
SessionDateUtils.INSTANCE.setYearOffset(year);
WorkArea wa = work.get();
if (wa.exports != null)
{
wa.exports.setYearOffset(year);
}
}
/**
* Get the PIXELS-PER-ROW attribute of this session.
*
* @return See above.
*/
public static integer getPixelsPerRow()
{
return new integer(LogicalTerminal.getClient().getPixelsPerRow());
}
/**
* Get the PIXELS-PER-COLUMN attribute of this session.
*
* @return See above.
*/
public static integer getPixelsPerColumn()
{
return new integer(LogicalTerminal.getClient().getPixelsPerColumn());
}
/**
* Sets the SESSION:TOOLTIPS attribute for this session.
*
* @param tooltips
* The new value for session related TOOLTIPS attribute.
*/
public static void setSessionTooltips(logical tooltips)
{
WorkArea wa = work.get();
// change the local copy
if (tooltips != null && !tooltips.isUnknown())
{
wa.tooltips = tooltips.booleanValue();
}
else
{
wa.tooltips = false;
}
// and push new value to the client
LogicalTerminal.getClient().setSessionTooltips(wa.tooltips);
}
/**
* Accesses the SESSION:TOOLTIPS attribute for this session.
*
* @return <code>true</code> if tooltips are available for this session
* <code>false</code> otherwise.
*/
public static logical getSessionTooltips()
{
WorkArea wa = null;
try
{
wa = work.get();
}
catch (Throwable e)
{
// NOTE: this is solely for debug: when the client stops with a strange NPE in
// ThinClient.setSessionTooltips(). This is the fist remote call so if things go
// wrong with initialization of the context on server-side here is the error
// accessible./visible.
LOG.severe("", e);
// rethrow
throw e;
}
return new logical(wa.tooltips);
}
/**
* Get THREE-D attribute value for SESSION handle.
*
* @return the attribute value
*/
public static logical is3D()
{
return LogicalTerminal.is3D();
}
/**
* Set THREE-D attribute value for SESSION handle.
*
* @param value
* The value to set.
*/
public static void set3D(logical value)
{
LogicalTerminal.set3D(value);
}
/**
* Get the state of SESSION:PRINTER-NAME attribute.
*
* @return the state of SESSION:PRINTER-NAME attribute.
*/
public static character getPrinterName()
{
return EnvironmentOps.getCurrentPrinterName();
}
/**
* Set the state of SESSION:PRINTER-NAME attribute.
*
* @param value
* The new state for SESSION:PRINTER-NAME attribute.
*/
public static void setPrinterName(character value)
{
// currently only the built-in PDF printer is supported, so this method is a no-op
}
/**
* Get the state of SESSION:PRINTER-PORT attribute.
*
* @return the state of SESSION:PRINTER-PORT attribute.
*/
public static character getPrinterPort()
{
// currently only the built-in PDF printer is supported, so this method always returns an unknown
return new character();
}
/**
* Set the state of SESSION:PRINTER-PORT attribute.
*
* @param value
* The new state for SESSION:PRINTER-PORT attribute.
*/
public static void setPrinterPort(character value)
{
readOnlyError("PRINTER-PORT");
}
/**
* Get the state of SESSION:PRINTER-CONTROL-HANDLE attribute.
*
* @return the state of SESSION:PRINTER-CONTROL-HANDLE attribute.
*/
public static integer getPrinterControlHandle()
{
return new integer(PrintingService.getControlHandle());
}
/**
* Set the state of SESSION:PRINTER-CONTROL-HANDLE attribute.
*
* @param value
* The new state for SESSION:PRINTER-CONTROL-HANDLE attribute.
*/
public static void setPrinterControlHandle(integer value)
{
PrintingService.resetControlHandle();
}
/**
* Get the state of SESSION:PRINTER-HDC attribute.
*
* @return the state of SESSION:PRINTER-HDC attribute.
*/
public static integer getPrinterHDC()
{
return new integer(PrintingService.getHDC());
}
/**
* The SESSION:GET-PRINTERS method.
*
* @return the result of SESSION:GET-PRINTERS method.
*/
public static character getPrinters()
{
// currently only the built-in PDF printer is supported
return new character(PrintingService.PDF_PRINTER_DESCR);
}
/**
* Get the state of SESSION:SUPPRESS-WARNINGS attribute.
*
* @return the state of SESSION:SUPPRESS-WARNINGS attribute.
*/
public static logical isSuppressWarnings()
{
return new logical(ErrorManager.isSuppressWarnings());
}
/**
* Set the state of SESSION:SUPPRESS-WARNINGS attribute.
*
* @param value
* The new state for SESSION:SUPPRESS-WARNINGS attribute.
*/
public static void setSuppressWarnings(logical value)
{
if (value.isUnknown())
{
// UNKNOWN is silently ignored
return;
}
setSuppressWarnings(value.booleanValue());
}
/**
* Set the state of SESSION:SUPPRESS-WARNINGS attribute.
*
* @param value
* The new state for SESSION:SUPPRESS-WARNINGS attribute.
*/
@LegacyAttribute(name = "SUPPRESS-WARNINGS", setter = true)
public static void setSuppressWarnings(boolean value)
{
ErrorManager.setSuppressWarnings(value);
}
/**
* Get the state of SESSION:STARTUP-PARAMETERS attribute.
*
* @return the state of SESSION:STARTUP-PARAMETERS attribute.
*/
public static character getStartupParameters()
{
return new character(startupParameters.get().toString());
}
/**
* Get the startup parameters.
*
* @return the startup parameters object.
*/
public static StartupParameters _startupParameters()
{
return startupParameters.get();
}
/**
* Sets the startup parameters.
*/
public static void setStartupParameters(StartupParameters startupParameters)
{
SessionUtils.startupParameters.set(startupParameters);
work.get().isDebugAlert = startupParameters.getDebugAlert();
work.get().errorStackTrace = startupParameters.getErrorStack();
}
/**
* Set the state of SESSION:SYSTEM-ALERT-BOXES attribute.
*
* @param on
* The new state for SESSION:SYSTEM-ALERT-BOXES attribute.
*/
public static void setSystemAlertBoxes(boolean on)
{
ErrorManager.setSystemAlertBoxes(on);
}
/**
* Set the state of SESSION:SYSTEM-ALERT-BOXES attribute.
*
* @param on
* The new state for SESSION:SYSTEM-ALERT-BOXES attribute.
*/
public static void setSystemAlertBoxes(logical on)
{
setSystemAlertBoxes(on == null || on.isUnknown() ? false : on.booleanValue());
}
/**
* Get the state of SESSION:SYSTEM-ALERT-BOXES attribute.
*
* @return the state of SESSION:SYSTEM-ALERT-BOXES attribute.
*/
public static logical isSystemAlertBoxes()
{
return new logical(ErrorManager.isSystemAlertBoxes());
}
/**
* Set the value of SESSION:MULTITASKING-INTERVAL attribute.
*
* @param interval
* The new value of SESSION:MULTITASKING-INTERVAL attribute.
*/
public static void setMultitaskingInterval(NumberType interval)
{
long val = interval.isUnknown() ? 0 : interval.longValue();
work.get().multitaskingInterval = val;
LogicalTerminal.getClient().setMultitaskingInterval(val);
}
/**
* Get the value of SESSION:MULTITASKING-INTERVAL attribute.
*
* @return the value of SESSION:MULTITASKING-INTERVAL attribute.
*/
public static integer getMultitaskingInterval()
{
return new integer(work.get().multitaskingInterval);
}
/**
* Set the value of SESSION:EXIT-CODE attribute.
*
* @param value
* The new value of SESSION:EXIT-CODE attribute.
*/
public static void setExitCode(long value)
{
// TODO: The exit code needs to get out of this call, and be returned from the JVM to the OS
work.get().exitCode = value;
}
/**
* Get the value of SESSION:EXIT-CODE attribute.
*
* @return the value of SESSION:EXIT-CODE attribute.
*/
public static long getExitCode()
{
return work.get().exitCode;
}
/**
* Get the SERVER-CONNECTION-BOUND attribute of this session.
*
* @return See above.
*/
public static logical isServerConnectionBound()
{
return AppServerManager.isServerConnectionBound();
}
/**
* Get the SERVER-CONNECTION-CONTEXT attribute of this session.
*
* @return See above.
*/
public static character getServerConnectionContext()
{
return new character(AppServerManager.getServerConnectionContext());
}
/**
* Set the SERVER-CONNECTION-CONTEXT attribute of this session.
*
* @param val
* The attribute's value.
*/
public static void setServerConnectionContext(String val)
{
AppServerManager.setServerConnectionContext(val);
}
/**
* Set the SERVER-CONNECTION-CONTEXT attribute of this session.
*
* @param val
* The attribute's value.
*/
public static void setServerConnectionContext(character val)
{
AppServerManager.setServerConnectionContext(val.getValue());
}
/**
* Get the value of SESSION:SERVER-CONNECTION-ID attribute.
*
* @return the value of SESSION:SERVER-CONNECTION-ID attribute.
*/
public static character getServerConnectionId()
{
String id = AppServerManager.getServerConnectionId();
return new character(id == null ? "" : id);
}
/**
* Get the FIRST-OBJECT attribute of this session.
*
* @return See above.
*/
public static object<?> firstObject()
{
handle obj = HandleChain.firstResource(LegacyResource.OBJECT);
return new object<>((ObjectResource) obj.get());
}
/**
* Get the LAST-OBJECT attribute of this session.
*
* @return See above.
*/
public static object<?> lastObject()
{
handle obj = HandleChain.lastResource(LegacyResource.OBJECT);
return new object<>((ObjectResource) obj.get());
}
/**
* Get the LOCAL-VERSION-INFO attribute of this session.
*
* @return See above.
*/
public static object<? extends OeversionInfo> localVersionInfo()
{
return ObjectOps.newInstance(OeversionInfo.class);
}
/**
* This is a helper method setting the value of OEClientType for the session's OeversionInfo.
* Not exposed in 4GL.
*
* @param clientTypes
* The client types for the session.
*/
public static void setClientTypes(ClientType... clientTypes)
{
work.get().clientTypes = clientTypes;
}
/**
* This is a helper method returning the value of OEClientType for the session's OeversionInfo.
* Not exposed in 4GL.
*
* @return See above.
*/
public static ClientType[] getClientTypes()
{
return work.get().clientTypes;
}
/**
* This is a helper method returning the value of OEClientType for the session's OeversionInfo.
* Not exposed in 4GL.
*
* @return See above.
*/
public static character getClientType()
{
ClientType[] clientTypes = work.get().clientTypes;
if (clientTypes == null || clientTypes.length == 0)
{
return new character();
}
List<String> validTypes = Arrays.stream(clientTypes)
.filter(clientType -> clientType != null && clientType != ClientType.UNKNOWN)
.map(ClientType::toString)
.collect(Collectors.toList());
return validTypes.isEmpty() ? new character() : new character(String.join(", ", validTypes));
}
/**
* Get the CURRENT-REQUEST-INFO attribute of this session.
*
* @return See above.
*/
public static object<? extends OerequestInfo> currentRequestInfo()
{
WorkArea wa = work.get();
if (!AppServerManager.isMultiSession() && !AppServerManager.isRemote())
{
// non-MSA appserver clients return unknown
return new object<>();
}
if (wa.currentRequestInfo == null)
{
wa.currentRequestInfo = new ObjectVar<>(OerequestInfo.class);
wa.currentRequestInfo.assign(ObjectOps.newInstance(OerequestInfo.class));
}
return new object<>(wa.currentRequestInfo);
}
/**
* Get the CURRENT-RESPONSE-INFO attribute of this session.
*
* @return See above.
*/
public static object<? extends OerequestInfo> currentResponseInfo()
{
WorkArea wa = work.get();
if (!AppServerManager.isMultiSession() && !AppServerManager.isRemote())
{
// non-MSA clients return unknown
return new object<>();
}
if (wa.currentResponseInfo == null)
{
wa.currentResponseInfo = new ObjectVar<>(OerequestInfo.class);
wa.currentResponseInfo.assign(ObjectOps.newInstance(OerequestInfo.class));
}
return new object<>(wa.currentResponseInfo);
}
/**
* Get the ICFPARAMETER attribute of this session.
*
* @return See above.
*/
public static character getICFParameter()
{
return new character(startupParameters.get().getDynamicsIcfParam());
}
/**
* Get the CONTEXT-HELP-FILE attribute of this session.
*
* @return See above.
*/
public static character getContextHelpFile()
{
return new character(work.get().contextHelpFile);
}
/**
* Set the CONTEXT-HELP-FILE attribute of this session.
*
* @param file
* The file name.
*/
public static void setContextHelpFile(String file)
{
work.get().contextHelpFile = file;
}
/**
* Set the CONTEXT-HELP-FILE attribute of this session.
*
* @param file
* The file name.
*/
public static void setContextHelpFile(character file)
{
work.get().contextHelpFile = file.getValue();
}
/**
* Get the SERVER-CONNECTION-BOUND-REQUEST attribute of this session.
*
* @return See above.
*/
public static logical getServerConnectionBoundRequest()
{
return AppServerManager.isServerConnectionBoundRequest();
}
/**
* Set the SERVER-CONNECTION-BOUND-REQUEST attribute of this session.
*
* @param state
* The bound state.
*/
public static void setServerConnectionBoundRequest(boolean state)
{
AppServerManager.setServerConnectionBoundRequest(state);
}
/**
* Set the SERVER-CONNECTION-BOUND-REQUEST attribute of this session.
*
* @param state
* The bound state.
*/
public static void setServerConnectionBoundRequest(logical state)
{
AppServerManager.setServerConnectionBoundRequest(state.booleanValue());
}
/**
* Set the ERROR-STACK-TRACE attribute of this session.
*
* @param state
* The attribute's state.
*/
public static void setErrorStackTrace(logical state)
{
work.get().errorStackTrace = state.booleanValue();
}
/**
* Set the ERROR-STACK-TRACE attribute of this session.
*
* @param state
* The attribute's state.
*/
public static void setErrorStackTrace(boolean state)
{
work.get().errorStackTrace = state;
}
/**
* Get the ERROR-STACK-TRACE attribute of this session.
*
* @return See above.
*/
public static logical isErrorStackTrace()
{
return logical.of(work.get().errorStackTrace);
}
/**
* Mark this context as the client has disconnected (due to an abend, socket disconnect, etc).
*/
static void clientDisconnected()
{
work.get().clientDisconnected = true;
}
/**
* Get the SUPPRESS-WARNINGS-LIST of this session.
*
* @return See above.
*/
public static character getSuppressWarningsList()
{
return new character(ErrorManager.getSuppressWarningsList());
}
/**
* Set the SUPPRESS-WARNINGS-LIST attribute of this session.
*
* @param list
* The warning code list.
*/
public static void setSuppressWarningsList(String list)
{
setSuppressWarningsList(new character(list));
}
/**
* Set the SUPPRESS-WARNINGS-LIST attribute of this session.
*
* @param list
* The warning code list.
*/
public static void setSuppressWarningsList(Text list)
{
ErrorManager.setSuppressWarningsList(list.value);
}
/**
* Returns the external IP of the end-user machine, where the js client runs. Available with web sessions
* only.
*
* @return See above.
*/
public static character getBrowserExternalIp()
{
return new character(work.get().browserExternalIp);
}
/**
* Setter for the external IP of the end-user machine, where the js client runs. Available with web
* sessions only.
*
* @param browserExternalIp
* The external IP of the end-user machine
*/
public static void setBrowserExternalIp(String browserExternalIp)
{
WorkArea wa = work.get();
if (wa.browserExternalIp == null)
{
wa.browserExternalIp = browserExternalIp;
}
}
/**
* Returns the TCP port of the end-user machine, on which the WebSocket runs in the browser. Available
* with web sessions only.
*
* @return See above.
*/
public static integer getBrowserPort()
{
return new integer(work.get().browserPort);
}
/**
* Setter for the TCP port of the end-user machine, on which the WebSocket runs in the browser. Available
* with web sessions only.
*
* @param browserPort
* The TCP port of the end-user machine, on which the WebSocket runs in the browser
*/
public static void setBrowserPort(int browserPort)
{
WorkArea wa = work.get();
if (wa.browserPort == null)
{
wa.browserPort = browserPort;
}
}
/**
* Returns the offset in minutes from UTC for the browser timezone. Available with web sessions only.
*
* @return See above.
*/
public static integer getBrowserTimezone()
{
return new integer(work.get().browserTimezone);
}
/**
* Setter for the offset in minutes from UTC for the browser timezone. Available with web sessions only.
*
* @param browserTimezone
* The offset in minutes from UTC for the browser timezone
*/
public static void setBrowserTimezone(int browserTimezone)
{
WorkArea wa = work.get();
if (wa.browserTimezone == null)
{
wa.browserTimezone = browserTimezone;
}
}
/**
* Returns the UTC datetime of the capture time for BROWSER-EXTERNAL-IP. Available with web sessions only.
*
* @return See above.
*/
public static datetime getIpCaptureTime()
{
Long ipCaptureTimestamp = work.get().ipCaptureTimestamp;
if (ipCaptureTimestamp == null)
{
return new datetime();
}
Date datetime = new Date(ipCaptureTimestamp);
return new datetime(datetime, TimeZone.getTimeZone("UTC"));
}
/**
* Setter for the datetime of the capture time for BROWSER-EXTERNAL-IP. Available with web sessions only.
*
* @param ipCaptureTimestamp
* The UTC timestamp of the capture time for BROWSER-EXTERNAL-IP
*/
public static void setIpCaptureTime(long ipCaptureTimestamp)
{
WorkArea wa = work.get();
if (wa.ipCaptureTimestamp == null)
{
wa.ipCaptureTimestamp = ipCaptureTimestamp;
}
}
/**
* Returns the external IP of the client machine.
*
* @return See above.
*/
public static character getClientExternalIp()
{
return new character(work.get().clientExternalIp);
}
/**
* Setter for the external IP of the client machine.
*
* @param clientExternalIp
* The external IP of the client machine
*/
public static void setClientExternalIp(String clientExternalIp)
{
WorkArea wa = work.get();
if (wa.clientExternalIp == null)
{
wa.clientExternalIp = clientExternalIp;
}
}
/**
* Returns the TCP port of the client machine.
*
* @return See above.
*/
public static integer getClientPort()
{
return new integer(work.get().clientPort);
}
/**
* Setter for the TCP port of the client machine.
*
* @param clientPort
* The TCP port of the client machine.
*/
public static void setClientPort(int clientPort)
{
WorkArea wa = work.get();
if (wa.clientPort == null)
{
wa.clientPort = clientPort;
}
}
/**
* Returns the offset in minutes from UTC for the client machine timezone.
*
* @return See above.
*/
public static integer getClientTimezone()
{
return new integer(work.get().clientTimezone);
}
/**
* Setter for the offset in minutes from UTC for the client machine timezone.
*
* @param clientTimezone
* The offset in minutes from UTC for the client machine timezone
*/
public static void setClientTimezone(int clientTimezone)
{
WorkArea wa = work.get();
if (wa.clientTimezone == null)
{
wa.clientTimezone = clientTimezone;
}
}
/**
* Returns the UTC datetime of the capture time for CLIENT-EXTERNAL-IP.
*
* @return See above.
*/
public static datetime getClientIpCaptureTime()
{
Long ipCaptureTimestamp = work.get().clientIpCaptureTimestamp;
if (ipCaptureTimestamp == null)
{
return new datetime();
}
Date datetime = new Date(ipCaptureTimestamp);
return new datetime(datetime, TimeZone.getTimeZone("UTC"));
}
/**
* Setter for the datetime of the capture time for CLIENT-EXTERNAL-IP.
*
* @param ipCaptureTimestamp
* The UTC timestamp of the capture time for CLIENT-EXTERNAL-IP
*/
public static void setClientIpCaptureTime(long ipCaptureTimestamp)
{
WorkArea wa = work.get();
if (wa.clientIpCaptureTimestamp == null)
{
wa.clientIpCaptureTimestamp = ipCaptureTimestamp;
}
}
/**
* Returns the client screen color depth.
*
* @return See above.
*/
public static integer getScreenColorDepth()
{
return new integer(work.get().screenColorDepth);
}
/**
* Setter for the client screen color depth.
*
* @param screenColorDepth
* The client screen color depth
*/
public static void setScreenColorDepth(int screenColorDepth)
{
WorkArea wa = work.get();
if (wa.screenColorDepth == null)
{
wa.screenColorDepth = screenColorDepth;
}
}
/**
* Returns the client screen height.
*
* @return See above.
*/
public static integer getScreenHeight()
{
return new integer(work.get().screenHeight);
}
/**
* Setter for the client screen height.
*
* @param screenHeight
* The client screen height
*/
public static void setScreenHeight(int screenHeight)
{
WorkArea wa = work.get();
if (wa.screenHeight == null)
{
wa.screenHeight = screenHeight;
}
}
/**
* Returns the client screen scaling factor.
*
* @return See above.
*/
public static decimal getScreenScalingFactor()
{
return new decimal(work.get().screenScalingFactor);
}
/**
* Setter for the client screen scaling factor.
*
* @param screenScalingFactor
* The client screen scaling factor
*/
public static void setScreenScalingFactor(float screenScalingFactor)
{
WorkArea wa = work.get();
if (wa.screenScalingFactor == null)
{
wa.screenScalingFactor = screenScalingFactor;
}
}
/**
* Returns the client screen width.
*
* @return See above.
*/
public static integer getScreenWidth()
{
return new integer(work.get().screenWidth);
}
/**
* Setter for the client screen width.
*
* @param screenWidth
* The client screen width
*/
public static void setScreenWidth(int screenWidth)
{
WorkArea wa = work.get();
if (wa.screenWidth == null)
{
wa.screenWidth = screenWidth;
}
}
/**
* Returns the user agent info of the browser where the js client runs. Available with web sessions only.
*
* @return See above.
*/
public static character getUserAgent()
{
return new character(work.get().userAgent);
}
/**
* Setter for the user agent info of the browser where the js client runs. Available with web sessions only.
*
* @param userAgent
* The user agent
*/
public static void setUserAgent(String userAgent)
{
WorkArea wa = work.get();
if (wa.userAgent == null)
{
wa.userAgent = userAgent;
}
}
/**
* Setter for the storage ID of the end-user (available with SSO).
*
* @param storageId
* The storage ID
*/
public static void setStorageId(String storageId)
{
WorkArea wa = work.get();
if (wa.storageId == null)
{
wa.storageId = storageId;
}
}
/**
* Getter for the storage ID of the end-user (available with SSO).
*
* @return The storage ID.
*/
public static String getStorageId()
{
return work.get().storageId;
}
/**
* Returns the first value of the login parameter.
*
* @param paramName
* The name of the login parameter.
*
* @return See above.
*/
public static character getLoginParam(character paramName)
{
return getLoginParam(paramName, 1);
}
/**
* Returns the first value of the login parameter.
*
* @param paramName
* The name of the login parameter.
*
* @return See above.
*/
public static character getLoginParam(String paramName)
{
return getLoginParam(paramName, 1);
}
/**
* Returns the index value of the login parameter.
*
* @param paramName
* The name of the login parameter.
* @param oeIndex
* The index of the value of the login parameter. 1-based as in Progress.
*
* @return See above.
*/
public static character getLoginParam(character paramName, integer oeIndex)
{
if (paramName == null || paramName.isUnknown() || oeIndex == null || oeIndex.isUnknown())
{
return new character();
}
return getLoginParam(paramName.toStringMessage(), oeIndex.intValue());
}
/**
* Returns the index value of the login parameter.
*
* @param paramName
* The name of the login parameter.
* @param oeIndex
* The index of the value of the login parameter. 1-based as in Progress.
*
* @return See above.
*/
public static character getLoginParam(character paramName, int oeIndex)
{
if (paramName == null || paramName.isUnknown())
{
return new character();
}
return getLoginParam(paramName.toStringMessage(), oeIndex);
}
/**
* Returns the index value of the login parameter.
*
* @param paramName
* The name of the login parameter.
* @param oeIndex
* The index of the value of the login parameter. 1-based as in Progress.
*
* @return See above.
*/
public static character getLoginParam(String paramName, integer oeIndex)
{
if (paramName == null || oeIndex == null || oeIndex.isUnknown())
{
return new character();
}
return getLoginParam(paramName, oeIndex.intValue());
}
/**
* Returns the index value of the login parameter.
*
* @param paramName
* The name of the login parameter.
* @param oeIndex
* The index of the value of the login parameter. 1-based as in Progress.
*
* @return See above.
*/
public static character getLoginParam(String paramName, int oeIndex)
{
if (paramName == null ||
work.get().loginParams == null ||
!work.get().loginParams.containsKey(paramName) ||
oeIndex < 1)
{
return new character();
}
int index = oeIndex - 1;
String[] values = work.get().loginParams.get(paramName);
if (values == null || values.length < index + 1)
{
return new character();
}
return new character(values[index]);
}
/**
* Sets the params sent by the login request. Available with web sessions only.
*
* @param loginParams
* The map of name : values for the params sent by the login request.
*/
public static void setLoginParams(Map<String, String[]> loginParams)
{
WorkArea wa = work.get();
if (wa.loginParams == null)
{
wa.loginParams = loginParams;
}
}
/**
* Returns all login parameters.
*
* @return See above.
*/
public static Map<String, String[]> getLoginParams()
{
return work.get().loginParams;
}
/**
* Returns comma delimited string of local file system paths of
* the files uploaded during direct upload or a comma delimited string
* of file names chosen during direct file upload.
*
* @return See above.
*/
public static character getWebUploadFiles()
{
WorkArea wa = work.get();
return new character(wa.webUploadFiles);
}
/**
* Returns {code true} when the current direct upload operation ended with
* an error, {@code false} otherwise.
*
* @return See above.
*/
public static logical getWebUploadError()
{
WorkArea wa = work.get();
return new logical(wa.webUploadError);
}
/**
* Assigns the upload information related to the current direct upload.
*
* @param uploadFiles
* Comma delimited string of local file system paths of
* the files uploaded during direct upload or a comma delimited string
* of file names chosen during direct file upload.
*
* @param error
* {code true} when the current direct upload operation ended with
* an error, {@code false} otherwise.
*/
public static void setWebUploadInfo(String[] uploadFiles, boolean error)
{
WorkArea wa = work.get();
wa.webUploadFiles = String.join(",", uploadFiles);
wa.webUploadError = error;
}
/**
* Returns a handle to the first asynchronous requests in the AppServer or WebService list of
* asynchronous requests.
*
* @return See above.
*/
public static handle getFirstAsyncRequest()
{
UnimplementedFeature.missing("SESSION:FIRST-ASYNC-REQUEST");
return new handle();
}
/**
* Returns a handle to the last asynchronous requests in the AppServer or WebService list of
* asynchronous requests.
*
* @return See above.
*/
public static handle getLastAsyncRequest()
{
UnimplementedFeature.missing("SESSION:LAST-ASYNC-REQUEST");
return new handle();
}
/**
* Stores global data relating to the state of the current context.
*/
private static class WorkArea
{
/** Cached instance of the SESSION resource. */
public CommonSession proxy = null;
/** The resource's ID. */
private Long id = null;
/** The session unique identifier. */
private String sessionId = null;
/** The unique ID of the original session that was forked. */
private String relatedSessionId = null;
/** Remote client interface. */
private SessionExports exports = null;
/** The state of SESSION:DEBUG-ALERT attribute */
private boolean isDebugAlert = startupParameters.get().getDebugAlert();
/** The flag indicating whether the widgets have the tooltip feature. */
private boolean tooltips = Utils.getDirectoryNodeBoolean(null, "session-tooltips", true);
/** This is just a holder for SESSION:MULTITASKING-INTERVAL. */
private long multitaskingInterval = 0;
/** The resultant value the 4GL may want to return to the OS (SESSION:EXIT-CODE) */
/*
* TODO: The return of this value needs to be implemented somewhere in the ConversionDriver
* so it can make its way back to the OS.
*/
private long exitCode = 0;
/** The value of the CONTEXT-HELP-FILE attribute. */
private String contextHelpFile = null;
/** The value of the CURRENT-REQUEST-INFO attribute. */
private object<OerequestInfo> currentRequestInfo = null;
/** The value of the CURRENT-RESPONSE-INFO attribute. */
private object<OerequestInfo> currentResponseInfo = null;
/** The value of the OEVersionInfo:OEClientType attribute. */
private ClientType[] clientTypes;
/**
* Flag indicating if the FWD client has disconnected (due to an abend, socket close, etc).
* Will be set to <code>true</code> by the FWD when {@link TransactionManager#abnormalEnd} is being
* called for an unrecoverable exception.
*/
private boolean clientDisconnected = false;
/**
* A hook which will be executed before the root top-level block terminates. Can specify either an
* external program or a static method reference following the
* <code>com.goldencode.Foo:someStaticMethod</code> syntax.
*/
private String terminationHook = null;
/**
* Flag indicating if the {@link ProError#getCallStack()} should be populated with the stacktrace when
* an legacy OO error is thrown.
*/
private boolean errorStackTrace = startupParameters.get().getErrorStack();
/** The authentication blob. */
private String authBlob;
/** The device ID. */
private String deviceId;
/**
* The external IP of the end-user machine, where the js client runs. Available with web sessions only.
*/
private String browserExternalIp;
/**
* The TCP port of the end-user machine, on which the WebSocket runs in the browser. Available with
* web sessions only.
*/
private Integer browserPort;
/** The offset in minutes from UTC for the browser timezone. Available with web sessions only. */
private Integer browserTimezone;
/** The UTC timestamp of the capture time for BROWSER-EXTERNAL-IP. Available with web sessions only. */
private Long ipCaptureTimestamp;
/** The external IP of the client machine. */
private String clientExternalIp;
/** The TCP port of the client machine. */
private Integer clientPort;
/** The offset in minutes from UTC for the client machine. */
private Integer clientTimezone;
/** The UTC timestamp of the capture time for CLIENT-EXTERNAL-IP. */
private Long clientIpCaptureTimestamp;
/**
* The client screen color depth. In web clients represents the value accessible from the browser.
*/
private Integer screenColorDepth;
/**
* The client screen height. In web clients represents the value accessible from the browser.
*/
private Integer screenHeight;
/**
* The client screen scaling factor. In web clients represents the value accessible from the browser.
*/
private Float screenScalingFactor;
/**
* The client screen width. In web clients represents the value accessible from the browser.
*/
private Integer screenWidth;
/** The user agent info of the browser where the js client runs. Available with web sessions only. */
private String userAgent;
/** The storage ID of the end-user (available with SSO). */
private String storageId;
/** The map of name : values for the params sent by the login request. */
private Map<String, String[]> loginParams;
/** The files uploaded during the direct upload */
private String webUploadFiles;
/** Indicates an error during direct file upload */
private boolean webUploadError;
}
}