Legacy Appserver Agents¶
It is possible to configure a FWD application server to replace an OpenEdge Application Server, which will allow inbound connections only from compatible Java code (using FWD APIs) or from another FWD server (configured as an appserver client).
Connections directly from an OpenEdge (either from an Application Server or from any 4GL client) are not supported. The reason for this is simple: FWD provides functional compatibility, it does not provide a binary-compatible version of the OpenEdge Application Server protocol.
In this chapter, when reading “appserver”, it needs to be interpreted as the FWD implementation of the legacy OpenEdge Application Server infrastructure (client or server).
When configuring a new FWD application server, it is important to first determine which appservers are exposed by this FWD server and to which appservers the FWD server will connect to. This chapter will describe what to look for and how to setup and configure each case.
Access to a remote appserver can be done using some special APIs exposed via network proxies, described by the following interfaces:
com.goldencode.p2j.util.AppServerEntry
- if communication with the remote appserver is done from the Java code.com.goldencode.p2j.util.AppServer
- to remotely launch an appserver.
Depending on the resource plugins defined in the directory, access to these interfaces might be specifically defined, in the net resource section. Beside these, no special ACLs are required to run an application server, assuming the ACLs required by the spawner tool are installed properly.
System Requirements¶
Special system requirements are needed only when the FWD server exposes one or more appservers: in this case, the spawner tool needs to be properly setup and configured. See the Application Server Installation chapter of this book, for details about how to install and configure the spawner tool.
Configuring an Appserver Client¶
When the converted code establishes connections to an appserver, it is important that each connection is configured to target a FWD server running that appserver. The first step is to gather all the appserver connection strings from the legacy code (the first argument in a 4GL CONNECT
method, which targets an appserver).
At runtime, these client configurations are found in a per-server node, named app_services
: first, the /server/<server-id>/app_services/
node will be searched; if not found, the /server/default/app_services/
node will be searched. The configuration for client appserver connections can not be split between the default and the per-server nodes; if the directory contains multiple server IDs, an app_services
node needs to be created for each FWD server, if the legacy appserver connections target different FWD servers; if all configurations are the same, then the node can be placed in the default section.
The legacy appservers are configured as children of the app_services
node: each child will have as name the name of the legacy appserver target. Thus, the appserver-specific outer structure will look like:
<node class="container" name="app_services"> <node class="container" name="<legacy-appserver-name1>"> ... </node> <node class="container" name="<legacy-appserver-name2>"> ... </node> ... </node>
Remember, we are no longer connecting to 4GL - we just map the CONNECT settings to the target FWD server.
The configuration specified by each child node will be split in two parts:- the first part related to the target FWD server and
- the second part related to the legacy appserver connection strings, which now target the specified FWD server.
Thus, each child of theapp_services
node will have this structure:
<node class="container" name="app_services"> <node class="container" name="<legacy-appserver-name1>"> <!-- FWD server configuration --> <node class="integer" name="p2j_port"> <node-attribute name="value" value="<port>"/> </node> <node class="string" name="p2j_host"> <node-attribute name="value" value="<host>"/> </node> <node class="string" name="p2j_account"> <node-attribute name="value" value="<account>"/> </node> <!-- legacy appserver configuration --> <node class="strings" name="aliases"> <node-attribute name="values" value="<alias1>"/> <node-attribute name="values" value="<alias2>"/> ... <node-attribute name="values" value="<aliasn>"/> </node> <node class="strings" name="nameservers"> <node-attribute name="values" value="<ns1>"/> <node-attribute name="values" value="<ns2>"/> ... <node-attribute name="values" value="<nsn>"/> </node> <node class="strings" name="hosts"> <node-attribute name="values" value="<host1>"/> <node-attribute name="values" value="<host2>"/> ... <node-attribute name="values" value="<hostn>"/> </node> <node class="integers" name="ports"> <node-attribute name="values" value="<port1>"/> <node-attribute name="values" value="<port2"/> ... <node-attribute name="values" value="<portn>"/> </node> <node class="strings" name="services"> <node-attribute name="values" value="<service1>"/> <node-attribute name="values" value="<service2>"/> ... <node-attribute name="values" value="<servicen>"/> </node> <node class="strings" name="defaults"> <node-attribute name="values" value="<default-ns1>"/> <node-attribute name="values" value="<default-ns2>"/> ... <node-attribute name="values" value="<default-nsn>"/> </node> </node> </node>
The following table describes each node which can be provided for a legacy appserver, and their mapping to the legacy parameter for CONNECT
method (all are mandatory):
Node Name | Type | CONNECT option | Description |
---|---|---|---|
p2j_port |
integer | n/a | This represents the secure port of the FWD server running this appserver. |
p2j_host |
string | n/a | This represents the host on which the target FWD server is running. |
p2j_account |
string | n/a | The FWD account used to authenticate on the remote FWD server. This account must be configured for passwordless login, and can be either a server or a process. |
aliases |
strings | -AppService | For non-direct connections, this represents the known application service aliases of this legacy appserver. |
nameservers |
strings | -H | For non-direct connections, this represents the name of the nameservers with which these legacy appserver service aliases were registered (IPs or host names). |
hosts |
strings | -H | For direct connections, this represents the name of the host(s) on which the legacy appserver was running. |
ports |
integers | -S | For direct connections, this represents the port(s) on which the legacy appserver was listening. For non-direct connections, this represents the port(s) on which the nameservers handling this appserver was listening. |
services |
strings | -S | For direct connections, this represents the network service name(s) on which the legacy appserver was connected. For non-direct connections, this represents the network service name(s) on which the nameservers handling this appserver was connected. |
defaults |
strings | n/a | A list of nameserver hosts on which this appserver was the default appserver. |
In cases when the AppServer client requests and the target AppServer are ran by the same FWD server, it is important for the FWD-specific settings (like p2jport
, p2j-host
) to be configured to the same port and host as the running FWD server. Otherwise, FWD will not be able to determine that this is a local connection and will attempt to establish a remote connection to that FWD server.
The settings in the 'legacy appserver configuration' section can be extracted from the AppServer connections in use by the converted application (this may exist in .pf
files or explicitly in the CONNECT
statement), from the ubroker.properties
file describing the AppServer or from the OpenEdge GUI screens used to define the AppServer.
When resolving the FWD server targeted by a legacy connection, the search will be done this way:
- if the
-S
option was not specified, then the port defaults to5162
. - if the
-H
option was not specified, then the host defaults tolocalhost
. - if
-DirectConnect
and-AppService
were not specified, then the default appservice is computed, for the namespace specified by the-H
option (this value will be assumed as specified for the-AppService
option). - using the information computed at the previous steps, it will return the name of the first appserver for which all of the following applies:
- connected in direct mode or the
-AppService
is part of the appserver's aliases - the host is part of the appserver's host
- the port is not specified or the port is part of the appserver's ports
- the network service name is not specified or is part of the appserver's network service names
- connected in direct mode or the
- If one of the above conditions does not apply, then the appserver configuration is ignored and the next one is checked. If none of the appserver configurations match, then the appserver connection fails.
Allowing more than one value for the various legacy connection options will allow to merge two or more legacy appserver machines into a single FWD server handling all requests for that appserver.
Configuring a FWD Server to Run a Legacy Appserver¶
An appserver exposed by a FWD Server needs to be configured in an appservers/<appserver-name>/
node, which will be searched in the /server/<server-id>/
or /server/default/
nodes; if the appservers/<appserver-name>/
node resides both in the default and per-server section, only the value read from the per-server section will be used. The appservers
node has as children one or more nodes having as directory type the appserver
type and as name the appserver's name exposed by this FWD Server (may or may not be the same as the legacy appserver name):
<node class="container" name="appservers"> <node class="appserver" name="<appserver-name1>"> ... </node> <node class="appserver" name="<appserver-name1>"> ... </node> ... <node class="appserver" name="<appserver-namen>"> ... </node> </node>
For a defined appserver, the following table described the possible configuration (which can be found in the OpenEdge GUI settings for an AppServer or the ubroker.properties
file):
Node Name | ubroker key | Type | Mandatory | Description |
---|---|---|---|---|
operating_mode | operatingMode | string | yes | The appserver's operating mode. One of the State-reset, State-aware , Stateless and State-free strings; the match is done case-insensitively. |
request_timeout | sessionTimeout | integer | yes | The amount of time (in seconds) to wait for an agent to be available, before attempting to auto-start a new one. |
auto_trim_timeout | autoTrimTimeout | integer | yes | The number of seconds waiting before auto-trimming (terminating) the agents, if they exceed the minimum capacity. |
propath | PROPATH | string | yes | Appserver's explicit propath, set for each Agent started by this appserver. |
initial_agents | initialSrvrInstance | integer | yes | The number of agents to start initially. |
min_agents | minSrvrInstance | integer | yes | The minimum number of agents required for this appserver, at any time. |
max_agents | maxSrvrInstance | integer | yes | The maximum number of agents which can be alive at one time. |
activate | srvrActivateProc | string | no | The appserver's activate procedure, empty value means “not specified”. |
deactivate | srvrDeactivateProc | string | no | The appserver's deactivate procedure, empty value means “not specified”. |
connect | srvrConnectProc | string | no | The appserver's connect procedure, empty value means “not specified”. |
disconnect | srvrDisconnProc | string | no | The appserver's disconnect procedure, empty value means “not specified”. |
startup | srvrStartupProc | string | no | The appserver's startup procedure, empty value means “not specified”. |
shutdown | srvrShutdownProc | string | no | The appserver's shutdown procedure, empty value means “not specified”. |
startup_parameter | srvrStartupProcParam | string | no | The parameter for the startup procedure. If not specified, the unknown value will be assumed. |
A fully configured node looks like:
<node class="appserver" name="<appserver-name>"> <node-attribute name="operating_mode" value="state-reset"/> <node-attribute name="request_timeout" value="15"/> <node-attribute name="auto_trim_timeout" value="1800"/> <node-attribute name="propath" value=".:"/> <node-attribute name="initial_agents" value="5"/> <node-attribute name="min_agents" value="5"/> <node-attribute name="max_agents" value="10"/> <node-attribute name="activate" value="activate.p"/> <node-attribute name="deactivate" value="deactivate.p"/> <node-attribute name="connect" value="connect.p"/> <node-attribute name="disconnect" value="disconnect.p"/> <node-attribute name="startup" value="startup.p"/> <node-attribute name="shutdown" value="shutdown.p"/> <node-attribute name="startup_parameter" value=""/> <!-- additional settings --> <node-attribute name="pasoe" value="false"/> <node-attribute name="project_token" value="[token-name]"/> <node class="container" name="properties"> <node class="string" name="[env-property-1]"> <node-attribute name="value" value="[value-1]"/> </node> <node class="string" name="[env-property-2]"> <node-attribute name="value" value="[value-2]"/> </node> ... <node class="string" name="[env-property-n]"> <node-attribute name="value" value="[value-n]"/> </node> </node> </node>which, in this example, is configured to initially start 5 Agents, and the runtime will not allow more than 10 Agents to be started. Note the section of additional settings which can be specified for an AppServer in FWD:
pasoe
- set this flag to true only if the AppServer is configured to run in PASOE-compatibility mode, not classic AppServerproject_token
- when the directory has settings for multiple projects, being run by the same FWD server, set this to the project's token, to identify other specific settings in the directoryproperties
- this is a key/value list of OS environment properties which need to be set when starting an AppServer Agent.
In the ubroker.properties
file, there exists a srvrStartupParam
setting which can specify a .pf
file with additional configuration.
Each configured appserver must have its own FWD process account, which will be used to authenticate and run the appserver's Agents. To map an appserver to a process account, specify the appserver
attribute at the process account. Also, each appserver can be configured to be started automatically, via the scheduler, by scheduling the appserver's process account to be started automatically, when the FWD application server starts. The process account configured to run an appserver will look like (is important for the <appserver-name>
to match a correctly configured appserver):
<node class="process" name="<process-id>"> <node-attribute name="appserver" value="<appserver-name>"/> ... </node>
and must have this mandatory configuration, to set the FWD Client(s) acting as appserver Agents in “background” mode:
<node class="container" name="clientConfig"> <node class="string" name="cfgOverrides"> <node-attribute name="value" value="client:driver:background=true"/> </node> </node>
This node must appear in the /server/{default | <server-id>}/runtime/<process-id>/clientConfig
(in the default runtime section or server's private runtime section).
- the
systemUser
, to specify a different OS user for the AppServer process, other than the default one outputToFile
, to specify a log file for the AppServer, likeclient_%appserver%_%pid%_%timestamp%_%userid%.log
.
Once the FWD process account(s) have been added, a certificate must be loaded in the FWD Server's directory, for each FWD Process account managing an AppServer. If you are using self-signed certificates and these were previously generated with FWD's Cryptography Setup Helper tool, you can use the same tool to generate the certificates and private keys for the newly added accounts (or, you can (re)generate self-signed certificates for all accounts, using the same tool). Otherwise, you must configure each process account with a certificate, following the Certificates instructions.
The scheduler task used to automatically start the appserver agents will look like:
<node class="container" name="scheduler"> <node class="job" name="<job-name>"> <node-attribute name="type" value="process" /> <node-attribute name="target" value="<process-id>" /> <node-attribute name="enabled" value="TRUE" /> <node-attribute name="mode" value="now" /> </node> </node>
Same as for the appserver name set at a process account, is important to match the process account name mentioned here with the actual process account configured for the appserver.
When the scheduler sees that a process associated with an appserver needs to be started, it will automatically start a number of agents as specified by the initial_agents
configuration. Later on, if a FWD Client is connected manually and determined to be for an appserver Agent, it will either add it to this appserver's agent pool or terminate it, if the pool reached its maximum capacity.
If the appserver is not needed to be started automatically, it can be started by using the ServerDriver
's -a <appserver>
option: this will connect to the remote FWD Server and instruct it to start the specified appserver, immediately. In both cases, a Appserver '<appserver-name>' was started sucessfully!
message will be added to the server log, if the launching completed properly.
Handling Client Requests¶
When a FWD server exposes one or more appservers, it is important to reserve a number of Dispatcher
threads, depending on the maximum expected number of simultaneous appserver requests. For each expected connection, two Dispatcher
threads need to be available:
- 1 thread to manage the client request
- 1 thread to manage asynchronous requests sent by this client. This includes CTRL-C processing or any other asynchronous request generated by the business logic.
Thus, the recommended number of Dispatcher
threads is twice the maximum number of simultaneous appserver requests.
This number can be reduced only if it is expected for the appserver clients to connect only from Java code (outside from a FWD server): to configure the client to connect in Conversation
mode, set the net:queue:conversation=true
in the client's bootstrap config. In this mode, a dedicated thread will be created to manage the client requests. All asynchronous requests will still be processed in a Dispatcher
thread, which is why there still needs to be threads allocated in the pool.
For the cases when the appserver client requests originate from a FWD server (from legacy 4GL code), it is not possible to connect in Conversation
mode; in these cases, the established session is virtualized over a single socket connection between the two FWD servers, which prohibits establishing a Conversation
mode. Thus, if it is expected to have appserver connections from legacy 4GL code, reserve a number of Dispatcher threads as described above (twice the maximum number of simultaneous connections from this FWD server).
© 2004-2017 Golden Code Development Corporation. ALL RIGHTS RESERVED.