Loose applications

Loose applications are applications that are assembled from multiple physical locations, which are provided to the run time through an XML file. Loose applications are compatible with Java EE and OSGi applications and offer advantages in a development environment.

Normally an application is contained under one directory or in one archive, with its content, modules, resources, classdata, and metadata at known locations within that directory. Using loose applications, the content of an application can be split between multiple physical locations.

What is a loose application?

A loose application is defined as a virtual directory that represents the application, where information can be located anywhere. Use of loose applications enables development tools to run applications where the related files are sourced directly from the workspace, bypassing the need for exporting. These related files may include Java classes, JavaServer Pages, or images. Loading these files straight from the workspace leads to a quicker build-run-debug cycle. The content is not located in a single directory, but might originate from various locations. These locations are detailed in an XML configuration file.

There are two primary methods to provide the XML file to Open Liberty:

Using the location attribute

Specify the XML file in the location attribute of the application configuration section, and make sure that the file name ends with .xml. If you specify application location="myapp.war", the runtime searches for a file named myapp.war.xml. However, if both myapp.war and myapp.war.xml exist, the Open Liberty runtime prioritizes myapp.war for running the application. The search rules for this method align with those of an application directory or an archive.

Using the application dropins folder

Directly place the XML file into the application dropins folder, adhering to the folder naming conventions and appending .xml to the end of the file name.

When you run the server package command with a loose application my_app.war.xml file that uses server variable substitution, those parts of the loose application having variable substitution are not packaged. Variable substitution does not take place when you use the server package command.

Loose Application Configuration Files

When using a loose application, the Open Liberty server employs a loose application configuration to locate application content, instead of locating it from a root directory or root archive. This configuration provides flexibility in how application content is organized and accessed. You can use the loose application configuration to locate application content in the following ways:

  • Map any physical directory or physical file to any location within the application.

    *For example:* You can map the root of the virtual application archive to one location on disk, such as a folder in an Eclipse project.
  • Map any physical JAR file or directory to any location as a nested archive.

    *For example:* Map an **external** `JAR` file into the application. This **external** `JAR` file might be the output of a Java project, packaged as a `JAR` file, and created at a physical location outside of the virtual application.
  • Map multiple physical sources to a single target location, also known as merging.

    *For example:* Map one or more `bin/output` folders onto the `WEB-INF/classes` folder. This might be necessary because of workspace preferences, corporate guidelines, or source control project layout guidelines. You may need multiple mapped folders if a project has several output locations or if multiple projects are mapped to the same `WEB-INF/classes` folder.
    *For example:* Include a utility `JAR` file somewhere else on your hard disk drive that you built the `.war` file against, and that you need to include in `WEB-INF/lib` at runtime.

Loose application configuration file examples

You can configure three different elements in the loose application configuration file:

  • archive for archives

  • file for files

  • dir for directories

The application name is taken from the application location. For example, If you locate the application at apps/myApp.war.xml, the Open Liberty server derives the application name from myApp.war.

Archives

The archive element is always used as the root of the loose application configuration file. It is also the root of the virtual file system that is represented in the XML. You can nest any of the three elements under the root archive element. The root archive element does not have any attributes.

The archive elements can be nested recursively. For archive elements nested under the root archive element, you can set the targetInArchive attribute. The targetInArchive attribute defines the path where the archive appears within the loose defined enclosing archive. You cannot map an archive on the file system as an archive in the application with an archive element. To use loose application configuration to map an archive on disk, use a file element instead.

The targetInArchive attribute value is an absolute path with a leading forward slash /.

The following is an example of the root archive element with another archive element nested under it:

<archive>
    <archive targetInArchive="/jarName.jar">
        <!-- more objects can be embedded here-->
    </archive>
</archive>

Files

You can use the file element to map a file on your hard disk to a file in your loose application configuration. You can set the following attributes on the file element:

  • targetInArchive attribute defines the path where the archive appears within the loose defined enclosing archive.

  • sourceOnDisk attribute defines the actual location of your file on your file system.

The sourceOnDisk attribute value is an absolute location. You can use Open Liberty variables such as ${example.dir}.

The following is an example of a file in C:/devFolder/myApplication.zip that is represented as /apps/webApplication.war by the loose application configuration:

<file targetInArchive="/apps/webApplication.war"
        sourceOnDisk="C:/devFolder/myApplication.zip" />

Directories

You can use the dir element to map a directory, and all of its contents on disk, to a directory location in the loose application configuration. The element has the same attributes as the file element and you use it in a similar way.

The following is an example of a directory that the loose application configuration shows as being in /META-INF and on your file system in ${example.dir}/applicationData/myApplication:

<dir targetInArchive="/META-INF"
       sourceOnDisk="${example.dir}/applicationData/myApplication" />

To add the directory to an archive so it appears to be in /apps/jarName.jar/META-INF, embed the dir element as follows:

<archive targetInArchive="/apps/jarName.jar">
    <dir targetInArchive="/META-INF"
           sourceOnDisk="${example.dir}/applicationData/myApplication" />
</archive>

In both of the previous examples, all files that are in ${example.dir}/applicationData/myApplication are mapped and visible in the loose application configuration under the directory that is mapped by the targetInArchive attribute.

Virtual paths and file names

If you add file or dir elements to an archive, the name of the file or directory in the loose archive does not need to be the same as the physical file name.

The example demonstrates how you can configure ${example.dir}/applicationFiles/newfile.txt to appear in the archive as /application.txt:

<archive>
    <file targetInArchive="/application.txt"
            sourceOnDisk="${example.dir}/applicationFiles/newfile.txt"/>
</archive>

The same concept also holds true for the path of any added file or directory. The physical resource on disk does not need to be in a directory hierarchy that corresponds to the one being declared.

The example demonstrates how to make ${example.dir}/applicationFiles/newfile.txt appear in the archive as /only/available/in/application.txt:

<archive>

    <file targetInArchive="/only/available/in/application.txt"
            sourceOnDisk="${example.dir}/applicationFiles/newfile.txt"/>

</archive>

In each case, the targetInArchive attribute declares the name and path by which the Open Liberty server sees the resource. The Open Liberty server can navigate the directory hierarchy declared, even if the hierarchy contains only virtual elements, as in the previous example.

<archive>
    <file targetInArchive="/only/available/in/red.txt"
            sourceOnDisk="${example.dir}/applicationFiles/newfile.txt" />
    <archive targetInArchive="/apps/jarName.jar">
        <dir targetInArchive="/META-INF"
               sourceOnDisk="${example.dir}/applicationData/myApplication" />
    </arhive>
</archive>

Mapping files or directories to the root of the archive

You can also map file or directory elements to the root location, /, of the enclosing archive.

For example, to use the contents of a folder as the contents of the virtual archive:

<archive>
    <dir targetInArchive="/"
         sourceOnDisk="c:/myapplication"/>
</archive>

To use the contents of an application archive as the contents of the virtual archive:

<archive>
    <file targetInArchive="/"
          sourceOnDisk="c:/myapplication.ear"/>
</archive>

Considerations for loose applications

For all loose configured applications, the files are not stored on disk in the hierarchy in which they are declared. If your applications access their resources directly and anticipate them to be organized on the disk in the same manner as an expanded war or ear layout, they can behave unexpectedly.

You can use ServletContext.getRealPath in your applications to discover physical resource paths. ServletContext.getRealPath can discover file paths to open to read or write data, and obtain directories. You can use ServletContext.getRealPath in your web applications to obtain a path for /, but you cannot use this path to navigate the application on disk.

When using loose applications, avoid relying on ServletContext.getRealPath to access physical files. Loose applications can merge multiple directories to provide content at one virtual path visible to the application, and ServletContext.getRealPath can provide only one of the mapped physical paths.

Consider the following configuration:

<archive>
    <dir targetInArchive="/"
           sourceOnDisk="c:\myapplication" />
    <dir targetInArchive="/web/pages"
           sourceOnDisk="c:\webpagesforapplication" />
</archive>

An application that directly accesses /web/pages and then navigates up the directory hierarchy finds that the parent of the physical path of /web/pages is c:\ and not /web. c:\ has no pages directory and no parent directory.

These considerations apply only if your applications attempt to directly access the content on disk, and perform their own path navigation based on an assumption of a corresponding hierarchical layout on disk. The same applications also encounter issues if they are deployed as an archive. These applications generally experience issues with portability.

Folders and files with the same name

If you map two folders to the same virtual location in the loose application configuration, the system merges the folders and makes the contents of both folders available. If you have two files with the same target location in the loose archive, the first occurrence of the file is used. The first occurrence is based on a top-down approach to reading the elements of the loose application configuration file. If the first file found is the wrong file to be used, reorder the XML so that the element that contains the version of the file you want is processed first.

The first occurrence applies to files defined in the dir elements and files that are defined in the file elements. The first occurrence of a file with the same name and virtual location is the one returned from the virtual file system.

Complex example

A more complex example of loose application configuration uses elements to create a complex mapping of files and directories as shown in the following example.

<archive>
    <dir targetInArchive="/appResources"
           sourceOnDisk="${example.dir}/applicationFiles" />
    <archive targetInArchive="application.jar">
        <dir targetInArchive="/src"
               sourceOnDisk="${example.dir}/applicationCode/src" />
    </archive>
    <archive targetInArchive="webApp.war">
        <dir targetInArchive="/META-INF"
               sourceOnDisk="${example.dir}/manifestFiles/" />
        <dir targetInArchive="/WEB-INF"
               sourceOnDisk="c:/myWorkspace/webAppProject/web-inf" />
        <archive targetInArchive="/WEB-INF/lib/myUtility.jar">
            <dir targetInArchive="/"
                   sourceOnDisk="c:/myWorkspace/myUtilityProject/src" />
            <file targetInArchive="/someJar.jar"
                    sourceOnDisk="c:/myWorkspace/myUtilityProject/aJar.jar" />
        </archive>
    </archive>
    <file targetInArchive="/myjar.jar"
            sourceOnDisk="${example.dir}/apps/application.zip" />
</archive>