Project

General

Profile

Hosting Custom Web Applications In-Process

Custom Web Application

Any Java-compliant web application packaged as a web archive (.war) can be deployed inside a running FWD server. Each application runs in its own embedded Jetty server instance, on its own port(s), isolated from FWD's own class path. This lets you co-locate a Spring Boot or plain Servlet API application with FWD and have it share the same JVM (and therefore Direct Java Access to the FWD runtime) without the two interfering with each other.

This page describes how to build, configure and deploy such an application.

Overview of the steps

  1. Build a working web application and package it as a .war file.
  2. Place the .war where the FWD server can find it.
  3. Create a server hook class (an InitTermListener) that starts the web app.
  4. Register the hook in the directory (server-hooks).
  5. Add the web application's configuration parameters in the directory.
  6. Recompile (ant jar) and deploy your project.
  7. Start the FWD server — the web app starts with it.

1. Build the web application

Build any standard Java web application — for example with the Spring Boot framework or the plain Servlet Java API — and package it as a .war file. The application must be a self-contained WAR: because FWD isolates the WAR's class loader from p2j.jar (see "Class loading and isolation" below), the WAR must bundle its own dependencies.

2. Place the WAR file

Copy the .war into the directory from which the FWD server is launched (its working directory), or into the same directory as p2j.jar.

GenericWebServer.getWarFile resolves the configured warfile value as follows:

  • If the value is an absolute path, it is used as-is.
  • Otherwise it is resolved relative to the directory that contains p2j.jar (the JAR from which GenericWebServer was loaded).

So an unqualified name such as myapp.war must sit next to p2j.jar; alternatively configure an absolute path in the directory.

3. Create a server hook

Server hooks run code during FWD startup and termination. The hook is responsible for registering (starting) and shutting down the web application.
Place the source file in your project (srcnew or src) so it is compiled into your project jar.

A hook implements com.goldencode.p2j.main.InitTermListener:

import com.goldencode.p2j.main.InitTermListener;
import com.goldencode.p2j.web.GenericWebServer;

public class MyAppHook
implements InitTermListener
{
   private GenericWebServer server;

   @Override
   public void initialize()
   {
      // name -> "MyApp"   : the directory hive is "MyAppWebApp" 
      // war  -> "myapp.war": default WAR name if "warfile" is not configured
      // thread name -> "MyAppThread": name of the thread running the Jetty instance
      server = GenericWebServer.initializeWebApp("MyApp", "myapp.war", "MyAppThread");
   }

   @Override
   public void terminate(Throwable t)
   {
      try
      {
         if (server != null)
         {
            server.shutdown();
         }
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }
   }
}

initialize() is called once during server startup; terminate() is called during shutdown and should stop the embedded Jetty instance via GenericWebServer.shutdown().

4. Register the hook in the directory

Server hooks are listed in a strings node named server-hooks, located under the server/standard node (the standard directory lookup rules apply, so it may also be placed under server/default or under a server-specific node). Each entry is the fully-qualified class name of an InitTermListener.

<node class="strings" name="server-hooks">
  <node-attribute name="values" value="com.example.MyAppHook"/>
</node>

At startup FWD reads this node, loads each listed class, and invokes its initialize() method.
(Only one hook may be assigned per resource jar.)

5. Add the web application configuration parameters

Add a container node for the web app under the server/standard directory node.
The container's name must be <web_app_name>WebApp, where <web_app_name> is the first argument passed to initializeWebApp (e.g. MyAppMyAppWebApp).

Example (replace the placeholders with actual values):

<node class="container" name="MyAppWebApp">
  <node class="string" name="keyStore">
    <node-attribute name="value" value="{key_store_path}"/>
  </node>
  <node class="string" name="storePassword">
    <node-attribute name="value" value="{store_password}"/>
  </node>
  <node class="string" name="entryPassword">
    <node-attribute name="value" value="{entry_password}"/>
  </node>
  <node class="integer" name="port">
    <node-attribute name="value" value="{insecure_port}"/>
  </node>
  <node class="integer" name="secureport">
    <node-attribute name="value" value="{secure_port}"/>
  </node>
  <node class="string" name="basepath">
    <node-attribute name="value" value="/my_app_base_path"/>
  </node>
  <node class="string" name="warfile">
    <node-attribute name="value" value="myapp.war"/>
  </node>
</node>

See "Directory parameters" below for the full list.

6. Recompile and deploy

Recompile your project with ant jar so the new hook class is included in your project jar, then deploy the updated jar to the server.

7. Run the server

Start the FWD server. During startup the server-hooks are loaded, your hook's initialize() runs, and initializeWebApp starts the embedded Jetty instance.
Startup is synchronous: the hook blocks until the web app reports that it has started (up to a 60-second timeout) and any startup failure is propagated as an exception, so a misconfigured web app surfaces immediately in the server log rather than failing silently in the background.

Class loading and isolation

Each web app runs with its own WebAppClassLoader. By default p2j.jar and most of FWD's dependencies are isolated from the web app, so the WAR can bundle different versions of common libraries without conflicting with FWD. Only the jars needed for the Jetty runtime hosting the web app remain visible to it — those whose names contain: javax.servlet-api, log4j, tuscany-sdo, jetty-, javax.websocket-, javax-websocket- and websocket-. Every other class-path entry is added to the server-class matcher (hidden from the web app).
This is why a custom WAR must be self-contained.

(One special case is handled: jasperreports_extension.properties is loaded only from within the web app rather than from parent class loaders.)

Directory parameters

All parameters live under the <web_app_name>WebApp container described above, i.e. the directory
path is <web_app_name>WebApp/<parameter_name>.

Name Type Mandatory Default value Description
port integer one of port/secureport n/a Port for incoming HTTP requests.
secureport integer one of port/secureport n/a Port for incoming HTTPS requests. A value > 0 enables HTTPS; when set, the keyStore/storePassword/entryPassword parameters are required.
host string no null The network interface the Jetty connector binds to, as an IP address or host name. 0.0.0.0 binds to all interfaces.
basepath string no "/" The context (base path) for all incoming requests. Trailing slashes are stripped.
warfile string no defaultWar argument The web archive file. Absolute path, or relative to the directory containing p2j.jar.
keyStore string yes if secureport > 0 n/a Java key store file holding the HTTPS server certificate.
storePassword string yes if secureport > 0 n/a Password to open the key store.
entryPassword string yes if secureport > 0 n/a Password for the private key entry in the key store.
sessionTimeout integer no 3600 HTTP session inactivity timeout, in seconds, and the housekeeping interval. A non-positive value falls back to 3600.
sniHostCheck boolean no false Whether the secure connector performs TLS SNI host checking.

Note: at least one of port or secureport must be configured. (In the previous version both were marked mandatory; that is no longer the case.) The secure-port directory node is spelled secureport (all lowercase).


© 2004-2026 Golden Code Development Corporation. ALL RIGHTS RESERVED.