Setup and Configuration of Legacy Appservers

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 class="container" name="<legacy-appserver-name2>">

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:
  1. the first part related to the target FWD server and
  2. the second part related to the legacy appserver connection strings, which now target the specified FWD server.
    Thus, each child of the app_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 class="string" name="p2j_host">
         <node-attribute name="value" value="<host>"/>
      <node class="string" name="p2j_account">
         <node-attribute name="value" value="<account>"/>
      <!-- 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 class="strings" name="nameservers">
         <node-attribute name="values" value="<ns1>"/>
         <node-attribute name="values" value="<ns2>"/>
         <node-attribute name="values" value="<nsn>"/>
      <node class="strings" name="hosts">
         <node-attribute name="values" value="<host1>"/>
         <node-attribute name="values" value="<host2>"/>
         <node-attribute name="values" value="<hostn>"/>
      <node class="integers" name="ports">
         <node-attribute name="values" value="<port1>"/>
         <node-attribute name="values" value="<port2"/>
         <node-attribute name="values" value="<portn>"/>
      <node class="strings" name="services">
         <node-attribute name="values" value="<service1>"/>
         <node-attribute name="values" value="<service2>"/>
         <node-attribute name="values" value="<servicen>"/>
      <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>"/>

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 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:

  1. if the -S option was not specified, then the port defaults to 5162.
  2. if the -H option was not specified, then the host defaults to localhost.
  3. 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).
  4. 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
    • 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 class="appserver" name="<appserver-name1>">
   <node class="appserver" name="<appserver-namen>">

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 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 class="string" name="[env-property-2]">
         <node-attribute name="value" value="[value-2]"/>
      <node class="string" name="[env-property-n]">
         <node-attribute name="value" value="[value-n]"/>
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 AppServer
  • project_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 directory
  • properties - this is a key/value list of OS environment properties which need to be set when starting an AppServer Agent.

In the 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>"/>

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"/>

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).

Otherwise, the FWD process account is configured the same way as the other FWD process accounts (see the Spawner Setup and Configuration chapter of this book for more details about how to configure this process account for automatic launching). From these, you can override:
  • 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, like client_%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 SSLCertGenUtil 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" />

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.