English ▼
Skip to page content Skip to main navigation
e.g. "templates" or "datastore"

# Java Application Configuration

In addition to the web.xml deployment descriptor, an App Engine Java application uses a configuration file, named `appengine-web.xml`, to specify the app's registered application ID and the version identifier of the latest code, and to identify which files in the app's WAR are static files (like images) and which are resource files used by the application. The AppCfg command uses this information when you upload the app.

- About appengine-web.xml
- Static Files and Resource Files
  - Including and Excluding Files
  - Setting the Browser Cache Expiration
  - Changing the MIME Type for Static Files
  - Changing the Root Directory
- System Properties and Environment Variables
- Configuring Secure URLs (SSL)
- Enabling Sessions
- Inbound Services
- Disabling Precompilation
- Administration Console Custom Pages
- Custom Error Responses
- Warmup Requests
- Using Concurrent Requests

## About appengine-web.xml

An App Engine Java app must have a file named `appengine-web.xml` in its WAR, in the directory `WEB-INF/`. This is an XML file whose root element is `<appengine-web-app>`. A minimal file that specifies the application ID, a version identifier, and no static files or resource files looks like this:

    <?xml version="1.0" encoding="utf-8"?>
    <appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
      <application>your_app_id</application>
      <version>1</version>
    </appengine-web-app>

The `<application>` element contains the application's ID. This is the application ID you register when you create your application in the Admin Console. When you upload your app, AppCfg gets the application ID from this file.

The `<version>` element contains the version identifier for the latest version of the app's code. The version identifier can contain letters, digits, and hyphens. AppCfg uses this version identifier when it uploads the application, telling App Engine to either create a new version of the app with the given identifier, or replace the version of the app with the given identifier if one already exists. You can test new versions of your app using a URL such as `http://version_id.latest.your_app_id.appspot.com`. You can select which version of the app your users see, the "default" version, using the Admin Console.

The `<static-files>` and `<resource-files>` elements are described in the next section.

You can find the DTD and schema specifications for this file in the SDK's `docs/` directory.

## Static Files and Resource Files

Many web applications have files that are served directly to the user's browser, such as images, CSS style sheets, or browser JavaScript code. These are known as static files because they do not change, and can benefit from web servers dedicated just to static content. App Engine serves static files from dedicated servers and caches that are separate from the application servers.

Files that are accessible by the application code using the filesystem are called resource files. These files are stored on the application servers with the app.

By default, all files in the WAR are treated as both static files and resource files, except for JSP files, which are compiled into servlet classes and mapped to URL paths, and files in the `WEB-INF/` directory, which are never served as static files and always available to the app as resource files.

You can adjust which files are considered static files and which are considered resource files using elements in the `appengine-web.xml` file. The `` element specifies patterns that match file paths to include and exclude from the list of static files, overriding or amending the default behavior. Similarly, the `` element specifies which files are considered resource files.

### Including and Excluding Files

Path patterns are specified using zero or more `<include>` and `<exclude>` elements. In a pattern, `*` represents zero or more of any character in a file or directory name, and `**` represents zero or more directories in a path.

An `<include>` element overrides the default behavior of including all files. An `<exclude>` element applies after all `<include>` patterns (as well as the default if no explicit `<include>` is provided).

The following example demonstrates how to designate all `.png` files as static files (except those in the `data/` directory and all of its subdirectories):

        <static-files>
            <include path="/**.png" />
            <exclude path="/data/**.png" />
        </static-files>

Similarly, the following sample demonstrates how to designate all `.xml` files as resource files (except those in the `feeds/` directory and all of its subdirectories):

        <resource-files>
            <include path="/**.xml" />
            <exclude path="/feeds/**.xml" />
        </resource-files>

### Setting the Browser Cache Expiration

You can specify a browser cache expiration time for static files. To do so, provide an `expiration` attribute to `<include ... >`. The value is a string of numbers and units, separated by spaces, where units can be `d` for days, `h` for hours, `m` for minutes, and `s` for seconds. For example, `"4d 5h"` sets cache expiration to 4 days and 5 hours after the file is first loaded by the browser. If the expiration time is omitted, the production server defaults to 10 minutes.

        <static-files>
            <include path="/**.png" expiration="4d 5h" />
        </static-files>

### Changing the MIME Type for Static Files

By default, static files are served using a MIME type selected based on the filename extension. You can associate custom MIME types with filename extensions for static files in web.xml using `` elements.

### Changing the Root Directory

Static files are served from the `public_root` directory. For the `java` runtime, this defaults to `/`. The following example changes public root from `/static/` to `/`, such that the application file `/static/index.html` is served as `/index.html`:

    <public-root>/static</public-root>

## System Properties and Environment Variables

The `appengine-web.xml` file can define system properties and environment variables that are set when the application is running.

        <system-properties>
            <property name="myapp.maximum-message-length" value="140" />
            <property name="myapp.notify-every-n-signups" value="1000" />
            <property name="myapp.notify-url" value="http://www.example.com/signupnotify" />
        </system-properties>

        <env-variables>
            <env-var name="DEFAULT_ENCODING" value="UTF-8" />
        </env-variables>

## Configuring Secure URLs (SSL)

By default, any user can access any URL using either HTTP or HTTPS. You can configure an app to require HTTPS for certain URLs in the deployment descriptor. See Deployment Descriptor: Secure URLs.

If you want to disallow the use of HTTPS for the application, put the following in the `appengine-web.xml` file:

        <ssl-enabled>false</ssl-enabled>

There is no way to disallow HTTPS for some URL paths and not others in the Java runtime environment.

## Enabling Sessions

App Engine includes an implementation of sessions, using the servlet session interface. The implementation stores session data in the App Engine datastore for persistence, and also uses memcache for speed. As with most other servlet containers, the session attributes that are set with `session.setAttribute()` during the request are persisted at the end of the request.

This feature is off by default. To turn it on, add the following to `appengine-web.xml`:

        <sessions-enabled>true</sessions-enabled>

The implementation creates datastore entities of the kind `_ah_SESSION`, and memcache entries using keys with a prefix of `_ahs`.

Note: Because App Engine stores session data in the datastore and memcache, all values stored in the session must implement the `java.io.Serializable` interface.

It's possible to reduce request latency by configuring your application to asynchronously write HTTP session data to the datastore:

        <async-session-persistence enabled="true" />

With async session persistence turned on, App Engine will submit a Task Queue task to write session data to the datastore before writing the data to memcache. By default the task will be submitted to the `default` queue. If you'd like to use a different queue, add the `queue-name` attribute:

       <async-session-persistence enabled="true" queue-name="myqueue"/>

Note: Note, session data is always written synchronously to memcache. If a request tries to read the session data when memcache is not available (or the session data has been flushed), it will fail over to the datastore, which may not yet have the most recent session data. This means that asynchronous session persistence may cause your application to see stale session data. However, for most applications the latency benefit far outweighs the risk.

## Inbound Services

Before an application can receive email and XMPP messages, the application must be configured to enable those services. You enable these services for a Java app by including an `<inbound-services>` element in the `appengine-web.xml` file. The following inbound services are available:

- `channel_presence` – registers your application for notifications when a client connects or disconnects from a channel.
- `mail` – allows your application to receive mail
- `xmpp_message` – allows your application to receive instant messages
- `xmpp_presence` – allows your application to receive a user's chat presence
- `xmpp_subscribe` – allows your application to receive user subscription POSTs.
- `warmup` – enables warmup requests

For example, you can enable mail and warmup by adding the following to `web.xml`:

      <inbound-services>
        <service>xmpp_message</service>
        <service>mail</service>
      </inbound-services>

## Disabling Precompilation

App Engine uses a "precompilation" process with the Java bytecode of an app to enhance the performance of the app in the Java runtime environment. Precompiled code functions identically to the original bytecode.

If for some reason you prefer that your app not use precompilation, you can turn it off by adding the following to your `appengine-web.xml` file:

      <precompilation-enabled>false</precompilation-enabled>

## Administration Console Custom Pages

If you have administrator-only pages in your application that are used to administer the app, you can have those pages appear in the Administration Console. The Administration Console includes the name of the page in its sidebar, and displays the page in an HTML iframe. To add a page to the Administration Console, add an `<admin_console>` section in your app's `appengine-web.xml` file, like so:

      <admin-console>
        <page name="Blog Comment Admin" url="/blog/admin/comments" />
        <page name="Create a Blog Post" url="/blog/admin/newentry" />
      </admin-console>

Note: Only custom pages defined by the default version will be shown in the Admin Console.

Each `<page>` represents a custom page. The `name` appears in the Administration Console navigation, and the `url` is the URL path to the page.

At this time, page names must contain only characters in the ASCII character set.

You can use configuration in the `web.xml` file to restrict access to custom administration pages to only users that are administrators of the app. See Security and Authentication.

## Custom Error Responses

When certain errors occur, App Engine serves a generic error page. You can configure your app to serve a custom static file instead of these generic error pages. You can set up different static files to be served for each supported error code by specifying the files in your app's `appengine-web.xml` file.

To serve custom error pages, add a `<static-error-handlers>` section to your `appengine-web.xml`, as in this example:

      <static-error-handlers>
        <handler file="default_error.html"/>
        <handler file="over_quota.html" error-code="over_quota"/>
      </static-error-handlers>

Warning!: Make sure that the path to the error response file does not overlap with static file handler paths.

Each `file` entry indicates a static file that should be served in place of the generic error response. The `error-code` indicates which error code should cause the associated file to be served. Supported error codes are as follows:

- `over_quota`, which indicates the app has exceeded a resource quota;
- `dos_api_denial`, which is served to any client blocked by your app's DoS Protection configuration;
- `timeout`, served if a deadline is reached before there is a response from your app.

The `error-code` is optional; if it's not specified, the given file is the default error response for your app.

You can optionally specify a `mime-type` to use when serving the custom error. See http://www.iana.org/assignments/media-types/ for a complete list of MIME types.

## Warmup Requests

App Engine frequently needs to load application code into a fresh instance. This happens when you redeploy the application, when the load pattern has increased beyond the capacity of the current instances, or simply due to maintenance or repairs of the underlying infrastructure or physical hardware.

Loading new application code on a fresh instance can result in loading requests. Loading requests can result in increased request latency for your users, but you can avoid this latency using warmup requests. Warmup requests load application code into a new instance before any live requests reach that instance.

App Engine attempts to detect when your application needs a new instance, and (assuming that warmup requests are enabled for your application) initiates a warmup request to initialize the new instance. However, these detection attempts do not work in every case. As a result, you may encounter loading requests, even if warmup requests are enabled in your app. For example, if your app is serving no traffic, the first request to the app will always be a loading request, not a warmup request.

Warmup requests use instance hours like any other request to your App Engine application. In most cases, you won't notice an increase in instance hours, since your application is simply initializing in a warmup request instead of a loading request. Your instance hour usage will likely increase if you decide to do more work (such as precaching) during a warmup request. If you set a minimum number of idle instance, you may encounter warmup requests when those instances first start, but they will remain available after that time.

The default warmup request causes all jar files to be indexed in memory and initializes your application and filters. The following sections describe how to configure warmup requests and create warmup logic for your application:

- Configuration
- Using a <load-on-startup> Servlet
- Using a ServletContextListener
- Using a Custom Servlet

### Configuration

Warmup requests are enabled by default for all Java applications.

If you configured your app with `web.xml`, you can implement warmup requests via an optional `<warmup-requests-enabled>` element in `appengine-web.xml`, which defaults to true. This causes the App Engine infrastructure to issue `GET` requests to `/_ah/warmup`, initializing <load-on-startup> servlets, ServletContextListeners, and custom servlets—which allow you to initialize your application's code as it requires. You may or may not need to implement your own hander for `/_ah/warmup` depending on which of these methods you choose.

To disable warmup requests, specify the `<warmup-requests-enabled>` element with a value of `false`:

    <warmup-requests-enabled>false</warmup-requests-enabled>

Warmup requests are not enabled by default if you configured your Java application with `app.yaml`. For details, please refer to Java Application Configuration Using app.yaml.

### Using a <load-on-startup> Servlet

The easiest way to provide warmup logic is to mark your own servlets as `<load-on-startup>` in `web.xml`. This method requires no changes to your application code, and initializes all specified servlets when your application initializes. The following example demonstrates how to load `my-servlet` on startup:

    <servlet>
      <servlet-name>my-servlet</servlet-name>
      <servlet-class>com.company.MyServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
    </servlet>

These lines load the specified servlet class and invoke the servlet's `init()` method. The warmup request initializes the specified servlets before servicing any live requests. However, if there is no warmup request, the servlets specified in `<load-on-startup>` are registered upon the first request to a new instance, which result in a loading request. As noted earlier, App Engine may not issue a warmup request every time your application needs a new instance.

### Using a ServletContextListener

If you have custom logic that you want to run before any of your servlets is invoked, the standard Java mechanism to arrange for that code to be executed is to register a ServletContextListener in `web.xml`.

    <listener>
     <listener-class>com.company.MyListener</listener-class>
    </listener>

And then supply a class alongside your servlet and filter code:

    public class MyListener implements ServletContextListener {
     public void contextInitialized(ServletContextEvent event) {
       // This will be invoked as part of a warmup request, or the first user
       // request if no warmup request was invoked.
     }
     public void contextDestroyed(ServletContextEvent event) {
       // App Engine does not currently invoke this method.
     }
    }

The ServletContextListener runs during a warmup request. If there is no warmup request, it runs upon the first request to a new instance. This may result in loading requests.

### Using a Custom Servlet

As noted earlier, the prediction algorithm to initiate warmup requests for new instances does not work in every case. Even with this feature enabled, you may encounter loading requests. If you use `<load-on-startup>` or `ServletContextListeners`, and the warmup request is not initiated, you may incur additional load time when a new instance starts to run. You can avoid this additional load time by providing a custom servlet that runs only during warmup requests. Custom servlets work best when you plan to have expensive logic (such as precaching) that runs only during a warmup request.

The custom warmup servlet invokes the warmup servlet's `service` method only during a warmup request. To create a custom warmup servlet, simply override the built-in servlet definition for `_ah_warmup` in `web.xml`:

    <servlet>
     <servlet-name>_ah_warmup</servlet-name>
     <servlet-class>com.company.MywarmupServlet</servlet-class>

## Using Concurrent Requests

By default, App Engine sends requests serially to a given web server. You can configure App Engine to send multiple requests in parallel by adding the `<threadsafe>` element to `appengine-web.xml`:

    <threadsafe>true</threadsafe>

Note: If you wish to use concurrent requests, your application code needs to use proper thread synchronization before you enable `<threadsafe>`.