Developing and deploying custom features
Starting with version 8.5.5, IBM WebSphere Application Server Liberty Profile supports direct enhancement of the runtime with user-defined features deployed in product extensions. Creating your own features allows you to customize or extend the behavior of the runtime using system programming interfaces (SPIs) that applications do not have access to. User-defined features can also provide additional application programming interfaces (APIs) and services to deployed applications.
This chapter walks through the creation, packaging, and deployment of a custom feature in the following sections:
9.1 Considerations for creating custom features
User-defined features become an integrated part of the runtime, allowing you to do things you cannot do with an application. The ways that applications are effected are as follows:
Features are installed and managed separately from business applications, keeping your runtime or product code separate from user code.
Services that are provided by a user-defined feature can receive user specified configuration from the server.xml file, and that configuration can be viewed and modified in the WebSphere developer tools configuration editor.
Classes in Open Service Gateway initiative (OSGi) bundles that are provisioned by a user-defined feature can use SPIs that are provided by the Liberty profile or by other extensions.
OSGi bundles in a user-defined feature can augment or extend supported programming models. For example, a custom Trust Association Interceptor (TAI) can be provided by a user-defined feature.
OSGi bundles in a user-defined feature can interact with OSGi services that are provided by the runtime and by other extensions. With correct metadata, OSGi services that are provided by user-defined features can also be shared with OSGi applications.
General instructions for writing features and receiving configuration properties can be found at the following website:
Consider the following list before you choose to extend the Liberty profile runtime:
Depending on your needs, features can run directly on the Liberty kernel with no dependence on application containers or other features. This approach provides a lightweight solution.
Defining your own features can be powerful, but comes at the cost of portability. If portability between application servers is a primary concern, developing specification-compliant applications is more appropriate than creating product extensions and features.
It is important to use only documented and supported externals to ensure that the Liberty profile can be serviced or upgraded with minimal disruption to your features and extensions. APIs, SPIs, and Javadoc are provided in the ${wlp.install.dir}/dev/ directory for use when developing and building your features.
Features can use OSGi management of native library loading, allowing you to package libraries for multiple architectures in a single JAR file. OSGi loads the appropriate library at runtime.
Other details about supported externals are provided in the IBM Knowledge Center section Liberty profile externals support (considered as the authoritative source) at this website:
9.2 Defining a custom feature
A Liberty profile feature is a collection of resources, usually OSGi bundles, that provide classes and services to the Liberty profile runtime. A feature is defined using a text-based manifest file that follows the Subsystem Service metadata format in the OSGi Enterprise R5 specification.
9.2.1 Elements of a feature
To create a feature, either manually or using WebSphere developer tools, you essentially must create a manifest file, example.mf, in the lib/features/ directory of a product extension. That manifest file must describe the feature with this type of information:
What it is called
How it is referenced
Whether other features can use it
Also, the manifest enumerates the feature’s content, including any bundles that should be provisioned if the feature is enabled.
For more information about feature manifests, including the full list of all supported manifest headers, see the following website:
Fixed-value manifest headers
There are a few headers in a feature manifest that must have specific, predefined values to allow the file to be recognized as a feature:
IBM-Feature-Version: 2
The version of the feature subsystem type. Required.
Subsystem-Type: osgi.subsystem.feature
The feature subsystem type. Required.
Subsystem-ManifestVersion: 1
The version of the OSGi Subsystem manifest format. Specifying this header is not required, but recommended.
Required manifest headers
The key elements of a feature definition (shown with a representative example value) are as follows:
Subsystem-SymbolicName: com.example.product.feature-1.0
The symbolic name of the feature, which follows the same style and syntax as the Bundle-SymbolicName header for bundles. Features can include other features, and when they do, they use the symbolic name to reference each other. The symbolic name of a feature should be sufficiently unique. It is safe to assume that two features with the same symbolic name are, in fact, the same feature. This header also supports the usage of attributes and directives, notably the visibility directive that is described in 9.2.2, “Visibility constraints for features, packages, and services” on page 233.
Subsystem-Content: com.example.product.bundle; version=”[1,1.0.100)”
This header is the key to provisioning. It is a comma-separated list of resources that defines the feature’s content. As with package declarations in a bundle manifest, each element of this list can specify additional directives, such as type, location, or version. These directives are described in more detail in 9.2.3, “Subsystem content: Writing a minify-compatible feature” on page 236.
Recommended headers for public features
Here are the recommended headers for public features:
IBM-ShortName: example-1.0
A representative short name that can be used with the extension name, in server.xml, to enable a feature. This is recommended to simplify the user configuration of public features.
Subsystem-Localization: OSGI-INF/l10n/localization
The name and description of a feature can be globalized. Use this header to package properties files containing the translated values with your feature.
Subsystem-Name: %name
A short, localizable, and descriptive feature name. You can specify the value directly, or use a %propertyName format, which looks up the translated value in the file that is referenced by the Subsystem-Localization header.
Subsystem-Description: %description
A short, localizable, and feature description. You can specify the value directly or use a %propertyName format, which looks up the translated value in the file that is referenced by the Subsystem-Localization header.
Subsystem-Version: 1.0.0.qualifier
The version of the feature. See the OSGi core specification section 3.2.5 for the details about how this is defined.
IBM-AppliesTo: com.ibm.websphere.appserver
The Liberty version that this feature applies to. You can specify a list of comma-delimited items, such as product_id, productVersion, productInstallType, and productEdition as in Example 9-1. If more than one item is supplied, the value for product_id must be different for each one.
Example 9-1 IBM-AppliesTo manifest header
IBM-AppliesTo: com.ibm.websphere.appserver; productVersion=8.5.5.5; productInstallType=Archive; productEdition="BASE,DEVELOPERS,EXPRESS,ND"
 
Subsystem-License: <site-name>/<license-document>
The license type for this feature. If this header is specified and you do not specify the IBM-License-Agreement and IBM-License-Information headers, the value of this header is displayed to the user for acceptance when installing.
IBM-License-Agreement: lafiles/LA
The prefix of the location of the license agreement feature. It contains the path to the LA<language> files in the Liberty installation directory.
IBM-License-Information: lafiles/LI
The prefix of the location of the license information feature files. It contains the path to the LI<language> files in the Liberty installation directory.
Headers that influence provisioning behavior
The (not required) headers that influence provisioning behavior are:
IBM-API-Package: javax.servlet; type=”spec”
A list of packages that follows the bundle manifest’s Export-Package syntax and lists the packages that are provided by a feature that should be visible to applications. For further information, refer to 9.2.2, “Visibility constraints for features, packages, and services” on page 233.
IBM-API-Service: com.example.service.FeatureServiceOne
This header is used to indicate which services from the feature are visible to OSGi applications. The services that are listed in this header must be registered in the service registry by the bundles that comprise the feature. The service-name is the Java class or interface name of the service. Any specified attributes are interpreted as service properties that should be used when providing the service to OSGi applications. For further information, refer to 9.2.2, “Visibility constraints for features, packages, and services” on page 233.
IBM-SPI-Package: com.example.spi.utils
A list of packages that follows the bundle manifest’s Export-Package syntax and lists packages that are provided by a feature that should be visible to other features in other extensions. For further information, refer to 9.2.2, “Visibility constraints for features, packages, and services” on page 233.
IBM-Provision-Capability: <OSGi LDAP Filter>
Some features provide a function that is only useful if other features are enabled. This header allows a feature to be auto-provisioned when its requirements, as specified in the feature definition using a standard OSGi LDAP filter, are satisfied. This header is described in more detail in 9.2.5, “Creating a Liberty feature manually” on page 242.
IBM-App-ForceRestart: install, uninstall
The presence of this header in a feature manifest causes applications to be restarted when this feature is either installed, uninstalled, or both.
9.2.2 Visibility constraints for features, packages, and services
The Liberty profile runtime imposes visibility constraints allowing both the core runtime and any installed extensions to evolve independently. By default, features and their associated bundles are considered internal details of the runtime or extension that provides them. The following list identifies what this default means:
All features are private and cannot be specified in server.xml or included by features from other extensions.
Exported packages are only visible to other bundles provided by the same extension.
Services that are registered in the service registry are not available to OSGi applications. Usage of registered services by consumers from other extensions is limited by the ability of consuming code to resolve the service interface.
The Subsystem-SymbolicName header supports a visibility attribute that controls how the feature can be used and resolved by the runtime and product extensions. As shown in Figure 9-1, there are three possible values for the visibility attribute: public, protected, and private (the default).
Figure 9-1 Visibility restrictions and features
Public features
Public features should be considered product externals or APIs. They can be used directly in server.xml files, are seen and used by the WebSphere developer tools, and appear in messages. Public features should have an IBM-ShortName header that is defined to simplify use. A list of public features that is provided by the Liberty runtime can be found in the following IBM support website:
A public feature might be superseded by a newer version if necessary, such that the older version that is used by existing server configurations continue to function. For more information about superseded features, see the following website:
Example 9-2 on page 235 shows a snippet from a public feature manifest. Observe the presence of the IBM-ShortName header, used in combination with the extension prefix in server.xml, and the public visibility constraint on the Subsystem-SymbolicName header.
Example 9-2 Declaration of a public feature, with an IBM-ShortName header
IBM-ShortName: example-1.0
Subsystem-SymbolicName: com.ibm.example.feature.public-1.0;
visibility:=public
Protected features
Protected features are also product externals, but should consider SPI, as the target consumer for a protected feature is another feature. Although protected features are not directly referenced in a configuration, they are referenced by other extensions and should be treated with an equal amount of care when changes are made to avoid breaking consumers.
The Liberty profile defines several protected features, including features for the application manager and the class loading service, for use by product extensions. A list of protected features provided by the Liberty runtime area are available in the IBM support website:
Example 9-3 shows a snippet from a protected feature manifest.
Example 9-3 Declaration of a protected feature
Subsystem-SymbolicName: com.ibm.example.feature.protected-1.0;
visibility:=protected
Private features
Private features are the default. Private features are usable only within a product extension. Implementation details should be packaged using private features. Auto features, described in 9.2.5, “Creating a Liberty feature manually” on page 242, are almost always private features. They rely on the provisioning of other public or protected features to automatically enable additional capabilities.
Example 9-4 shows a snippet from a private feature manifest.
Example 9-4 Declaration of a private feature, which omits the visibility attribute
Subsystem-SymbolicName: com.ibm.example.feature.private-1.0
Declaring API and SPI packages that are provided by a feature
By default, the individual packages that are exported by the bundles provisioned by a feature are private to the feature’s extension. This means that the individual packages that the bundles use to comprise your features are treated as internal implementation details for your product extension. Packages that should be shared with applications (as API) or with bundles from features in other extensions (as SPI) must be explicitly declared using manifest headers that follow the bundle’s Export-Package syntax.
The IBM-SPI-Package header is used to list packages that are provided by a feature that should be treated as SPI. The IBM-API-Package header is used to list packages that are provided by a feature that should be treated as API. Both headers support an optional type attribute that identifies the type of package that is being shared. The type attribute uses the following values:
api This value applies only to the IBM-API-Package header and is the default type for API package declarations. It is used to mark user-defined or product-defined API.
ibm-api This value applies only to the IBM-API-Package header and is used for IBM-provided API packages.
internal This value applies only to the IBM-API-Package header and is used to indicate packages that are not API packages. However, they must be available to application classloaders in order for them to function correctly. For example, because of the use of reflection, bytecode enhancement or weaving, and resource injection.
spec Used for API or SPI provided by a standards body such as, javax.servlet or org.osgi.framework.
third-party Used for API or SPI to show that it is visible. However, these items are not provided or controlled by IBM. This situation usually applies to open source packages. Use of third-party packages carries additional risk for version-to-version migration, as these packages might change over time without consideration for compatibility with earlier versions.
 
Note: When enumerating API and SPI packages, the package version is not specified. The package versions should be maintained only by the bundles that provides those packages.
You can see all feature manifest files of your Liberty profile in the /lib/features directory. For example, the values of the restConnector-1.0 feature are:
IBM-API-Package: com.ibm.websphere.jmx.connector.rest; type=”ibm-api”,com.ibm.ws.jmx.connector.client.rest; type=”ibm-api”,com.ibm.websphere.filetransfer; type=”ibm-api”
IBM-SPI-Package: com.ibm.wsspi.collective.plugins; type=”ibm-spi”, com.ibm.wsspi.collective.plugins.helpers; type=”ibm-spi”
9.2.3 Subsystem content: Writing a minify-compatible feature
The package utility, which is mentioned in 8.2, “Using the package utility” on page 217, can produce a minified server image. When you package a server with the --include=minify option, the package utility creates an archive that contains resources that only the server configuration requires. The list of required resources is built using the Subsystem-Content header that is defined for each enabled feature. When you create your own feature, it is important to verify the value of this header to ensure that a minified server that uses your feature has all of the resources that it needs.
The Subsystem-Content header follows the syntax shown in Example 9-5. As with an Export-Package bundle header, it is a comma-separated list of values, with optional semi-colon separated parameters, which can be attributes (=) or directives (:=). Each item in the list identifies an individual resource using a unique name.
Example 9-5 Syntax for Subsystem-Content header (see OSGi core spec section 1.3.2)
Subsystem-Content ::= resource ( ',' resource )*
 
resource ::= unique-name ( ';' parameter )*
 
unique-name ::= identifier ( ’.’ identifier )*
 
parameter ::= directive | attribute
directive ::= extended ’:=’ argument
attribute ::= extended ’=’ argument
 
argument ::= extended | quoted-string
extended ::= ( alphanum | ’_’ | ’-’ | ’.’ )+
quoted-string ::= ’"’ ( ~["#x0D#x0A#x00] | ’"’|’\’)* ’"’
The name that is used for a resource is influenced by its type, which is specified as an optional attribute. By default, a resource is assumed to be an OSGi bundle (type=”osgi.bundle”). The bundle’s symbolic name is used when specifying a bundle resource. Likewise, a feature’s symbolic name is used, along with type=”osgi.subsystem.feature”, to include another feature as a resource. For other supported types (type=”file” and type=”jar”) a unique string should be created for the resource using the syntax and character set that is allowed for symbolic or package names.
Resources can also specify a location directive to indicate where the artifact for that resource can or should be found. The specified location is also dependent on the type. The directive is not required for bundles or features, as the default (lib/ and lib/features/, respectively) is sufficient. For bundles and JAR files, the location directive can point to a list of directory locations, which constitute a search path (such as, look in dev/ first, then in lib/). The core runtime uses this list mechanism to provide API and SPI JAR files in the dev/ directory that are then serviced by the lib/ directory. For JAR and plain files, the location can (and in the case of files, must) contain a single path pointing directly to the backing resource. Paths are specified relative to the installation root of the extension containing the feature. When referencing public or protected features from another extension, the location field should not be specified. Rely on the symbolic name of the feature you are referencing and let the runtime figure out where to load it from.
In addition to type, the following list notes other supported directives:
version The version attribute applies to bundles and specifies the versions to be matched when finding a bundle to satisfy the feature. Only bundles in this range are selected. A typical example of the version range is (1,1.0.100).
start-phase Start-phase is a directive that indicates when (relative to the rest of the runtime) a bundle that is used by a feature should be started. The start-phase directive can take one of the following values: SERVICE, CONTAINER, or APPLICATION. Bundles can also be defined to start before or just after these phases by adding _LATE to be later or _EARLY to be earlier than the key phase. So if you want to run immediately after the container phase, use CONTAINER_LATE, and if you want to run before the APPLICATION phase, use APPLICATION_EARLY.
The next sections provide examples of these directives in use.
9.2.4 Using the tools to create a custom feature
In this section, we describe how to build a simple feature containing a single bundle that prints “Hello World!” when it is started, and “Goodbye World!” when it is stopped. The focus here is on creating a feature and the supporting bundle resource, publishing the feature to a product extension, and finally using the feature as the catalyst to cause our bundle to be loaded and started by the OSGi runtime.
Creating an OSGi bundle project
Begin by creating a project for this bundle by completing the following steps:
1. Click File → New → OSGi Bundle Project.
2. Enter a project name. This example uses the project name ITSO.OSGiExample.SimpleBundle.
3. For the Target Runtime, select WebSphere Application Server V8.5 Liberty Profile.
4. Clear the Add bundle to application check box. If you leave this selected, a new OSGi application project is created.
5. Leave all other values at the default settings and click Next → Next accepting all defaults.
6. This example uses a simple BundleActivator to show that the bundle is loaded by the runtime. Select the Generate an activator check box.
7. Exit the wizard by clicking Finish. The contents of the new bundle project should resemble what is shown in Figure 9-2.
Figure 9-2 OSGi bundle project with generated Activator
8. Update the contents of the Activator to roughly match the example contents of Figure 9-3.
Figure 9-3 Simple bundle activator
Creating a Liberty feature project
Begin by creating a project for the new feature by completing the following steps:
1. Click File → New → Other → OSGi Liberty Feature Project and then click Next to open the Liberty Feature Project wizard, as shown in Figure 9-4 on page 239.
Figure 9-4 The Liberty Feature Project wizard
2. Enter a project name. This example uses the project name ITSO.OSGiExample.SimpleFeature.
3. For the Target runtime, select WebSphere Application Server V8.5 Liberty Profile and click Next.
4. Select the check box next to itso.osgiexample.simplebundle to include our example bundle in our new feature as shown in Figure 9-5.
Figure 9-5 Adding a bundle to a feature
5. Exit the wizard by clicking Finish. The contents of the new feature project should resemble what is shown in Figure 9-6.
Figure 9-6 Liberty feature project
6. Double-click the Manifest element in the feature project to open the manifest editor. Update the values in the manifest (Figure 9-7) and save your changes. Specifically, update the feature’s symbolic name and the feature name to include a version representation. This is counter to how versions usually work. In this case, consider the version string in the feature name to be a statement of API/SPI compatibility, especially for public features.
Figure 9-7 The feature manifest editor
7. To support making changes to the bundle version (to apply service), select the bundle from the Subsystem-Content section of the editor, click Properties, and edit the Minimum Version and Maximum Version fields (Figure 9-8 on page 241). Click OK.
Figure 9-8 Editing the properties of a bundle that are listed in a feature’s Subsystem-Content
8. Click the SUBSYSTEM.MF tab at the bottom of the manifest editor to view the raw source of the manifest, resembling what is shown in Figure 9-9. The specified Subsystem-Content is minimal, as the feature includes only a bundle resource (which is the default type) in a default location with the specified required version range.
Figure 9-9 Raw contents of the feature manifest
Installing the feature
The WebSphere developer tools make installing the feature painless. Right-click the feature project, select Install Feature from the menu, select WebSphere Application Server V8.5 Liberty Profile for the target run time, and click Finish. The WebSphere developer tools adds the feature and its contents to the default product extension of the target run time (Figure 9-10). You need to restart the server in case it is running.
Figure 9-10 The example bundle and feature that is installed into the default product extension
Enabling the feature in a test server
Use the server configuration editor to edit the configuration of a test server by clicking Add next to the Feature Manager list and selecting the feature that we created from the list. Because it is a feature in the default product extension, it appears in the list with a usr: prefix. This example shows usr:simple-1.0 (Figure 9-11). Click OK to finish, and save the updated server configuration.
Figure 9-11 The simple-1.0 feature appears in the feature list with the usr: prefix
If you add this feature to a running server, you see something similar to the output shown in Example 9-6. “Hello World!” is the output from the simple activator that we provided for the feature bundle.
Example 9-6 Console output after enabling the usr:simple-1.0 feature.
[AUDIT ] CWWKF0011I: The server simpleServer is ready to run a smarter planet.
[AUDIT ] CWWKG0016I: Starting server configuration update.
Hello World!
[AUDIT ] CWWKF0012I: The server installed the following features: [usr:simple-1.0].
[AUDIT ] CWWKF0008I: Feature update completed in 0.220 seconds.
[AUDIT ] CWWKG0017I: The server configuration was successfully updated in 0.236 seconds.
9.2.5 Creating a Liberty feature manually
You can always create and deploy a Liberty feature manually, without the need of WebSphere Tools.
The two things that you need in order to obtain a Liberty feature are the OSGi bundle and the corresponding feature manifest file. The OSGi bundle has to be copied in the ${wlp.user.dir}/extension/lib directory and the manifest file has to be copied into the ${wlp.user.dir}/extension/lib/features directory. By doing these two things, you are able to finally install the new feature by adding its short name into the server.xml configuration file of the Liberty profile server.
To create a Liberty feature manually, follow the steps below:
1. Develop the OSGi bundle and the bundle manifest. It is required that the OSGi bundle manifest file contains the Bundle-SymbolicName header to specify a unique name for the bundle. Use the Export-Package header to specify the exported packages as in Example 9-7.
Example 9-7 Manifest file of an OSGi bundle
Bundle-SymbolicName: com.morleyc.example
Bundle-Version: 1.0.7
Bundle-ManifestVersion: 3
Export-Package: com.morleyc.example.testp1; version="1.0.3",
com.morleyc.example.testp2; version="1.0.1",
com.morleyc.example.testp3; version="1.0.7"
2. Package the OSGi bundle Java classes and the manifest file by using the jar command as in Example 9-8.
Example 9-8 Packaging the Java classes and the manifest file by using the jar command
jar cfm example.jar MANIFEST.Mf *.class
3. Create the manifest file of the new Liberty profile custom feature by adding the required and the recommended headers as explained in 9.2.1, “Elements of a feature” on page 231. Example 9-9 shows such a manifest file named new-feature-1.0.mf.
Example 9-9 The contents of the custom Liberty profile feature new-feature-1.0.mf file
Subsystem-ManifestVersion: 1.0
Subsystem-SymbolicName: com.morleyc.example.new-feature-1.0; visibility:=public
Subsystem-Version: 1.0.0.qualifier
Subsystem-Type: osgi.subsystem.feature
Subsystem-Content: example; version="[1,1.0.100)"
IBM-Feature-Version: 7
IBM-API-Package: com.morleyc.example.testp1; type="api",
com.morleyc.example.testp2; type="api",
com.morleyc.example.testp3; type="api"
IBM-SPI-Package: com.new-feature.myservice.spi;
IBM-ShortName: new-feature-1.0
4. Copy the bundle of the new Liberty profile feature into the ${wlp.user.dir}/extension/lib directory.
5. Copy the new Liberty profile feature manifest file into the ${wlp.user.dir}/extension/lib/features directory.
6. If defined by the Subsystem-Name, Subsystem-Description, and Subsystem-Localization headers, copy the localization files into the ${wlp.user.dir}/extension/lib/features/l10n directory.
7. Add the new feature to the Liberty profile server.xml configuration file as in Example 9-10.
Example 9-10 Adding the new feature in the server.xml Liberty profile configuration file
<featureManager>
<feature>usr:new-feature-1.0</feature>
</featureManager>
9.2.6 Automatic provisioning: Creating an auto-feature
An automatic feature is not configured by the user in the server XML. It is automatically loaded by the feature manager if the features specified in its IBM-Provision-Capability manifest header are configured by the user. This is useful when two features require additional Java classes to work together. The additional classes are put into the automatic feature. When only one of those features is configured, the extra Java classes are not loaded. In this way, automatic features can be used to keep features as small as possible without requiring the user to understand any relationships between them.
For example, one feature might provide an application container and another might provide a generic security service. In order for them to work together, security collaborators specific to that container are required. Those collaborators are not useful in the absence of either the container or the security service. In this example, the security collaborator classes are packaged into a third, automatic feature, which contains the entry in its manifest file shown in Example 9-11.
Example 9-11 Entry for automatic feature
IBM-Provision-Capability:
osgi.identity; filter:=”(&(type=osgi.subsystem.feature)(osgi.identity=com.ibm.itso.container))”,
osgi.identity; filter:=”(&(type=osgi.subsystem.feature)(osgi.identity=com.ibm.itso.security))”
The syntax for the IBM-Provision-Capability header is an LDAP query. The feature names that are specified in the query must be the Subsystem-SymbolicName values, not the IBM-ShortName values.
The bundles in the automatic feature can have mandatory dependencies on the bundles in both of the other features because the feature is provisioned only when both the container and security features are present. This is another way that automatic features helps minimize the mandatory dependencies between configured features.
9.2.7 Packaging native code in your bundles
OSGi provides help for loading native libraries. You can package libraries for all supported architectures in your bundle and list them on the Bundle-NativeCode manifest header. Code a single System.loadLibrary call in your Java code. OSGi examines the manifest header, determines the correct library for the architecture being used, and loads that library. Example 9-12 shows an example definition of the native library name for Windows and OSX.
Example 9-12 Definition of the native library name for Windows and OSX
Bundle-NativeCode:
lib/win32/x86/name.dll; osname=win32; processor=x86,
lib/macosx/libname.dylib; osname=macosx; processor=x86; processor=x86_64
Java has some limitations when loading native libraries that also apply in an OSGi framework. For example, a native library can be loaded only by one classloader in a JVM process, so the same native library cannot be used by more than one OSGi bundle.
9.2.8 Packaging features for delivery
Features can be packaged individually for an application to an existing Liberty profile installation or can be included in a packaged server if a self-contained deployment package is required.
OSGi subsystem archive
A subsystem archive is the OSGi-specified package for an individual feature. It contains the feature (subsystem) manifest and the files that are described by the Subsystem-Content manifest header. It is an archive file with an .esa suffix.
A subsystem archive is the output of WebSphere developer tools when you select Export for a Liberty feature project and can be applied to a Liberty profile installation by running the featureManager install command in the bin directory.
Packaged server
If you want to create a complete deployment solution, you can generate an archive by running the server package command. This outputs a compressed file with the following contents:
The Liberty runtime
Any features in the user product extension directory (wlp/usr/extension)
Your server configuration (for the server that is specified on the server package command)
Any applications and resources that are contained within the server
Using the minify option generates a smaller package containing only the features that are used by the server as in Example 9-13. This includes features that are configured in the server.xml file, features that are included by configured features, and features that are resolved as automatic features from the configured features. For example, a minified server package for servlet support is only about 17 MB.
Example 9-13 Using the server package command with and without the minify option
C:IBMWebSphereLiberty855_OSGIin>server package server --include=minify
Packaging server server.
Querying server server for content.
Launching server (WebSphere Application Server 8.5.5.5/wlp-1.0.8.cl50520150305-2202) on Java HotSpot(TM) 64-Bit Server VM, version 1.7.0_79-b15 (en_US)
[AUDIT ] CWWKE0001I: The server server has been launched.
[AUDIT ] CWWKF0012I: The server installed the following features: [servlet-3.0].
[AUDIT ] CWWKF0026I: The server server is ready to build a smaller package.
[AUDIT ] CWWKE0036I: The server server stopped after 6.825 seconds.
Building archive for server server.
Server server package complete in C:IBMWebSphereLiberty855_OSGIusrserversserverserver.zip.
C:IBMWebSphereLiberty8555_OSGIin>dir C:IBMWebSphereLiberty8555_OSGIusrserversserverserver.zip
Volume in drive C has no label.
Volume Serial Number is 3031-6CBE
Directory of C:IBMWebSphereLiberty8555_OSGIusrserversserver
05/08/2015 03:47 PM 43,945,347 server.zip
1 File(s) 43,945,347 bytes
0 Dir(s) 8,905,318,400 bytes free
C:IBMWebSphereLiberty8555_OSGIin>
C:IBMWebSphereLiberty8555_OSGIin>server package server
Packaging server server.
Server server package complete in C:IBMWebSphereLiberty8555_OSGIusrserversserverserver.zip.
C:IBMWebSphereLiberty8555_OSGIin>dir C:IBMWebSphereLiberty8555_OSGIusrserversserverserver.zip
Volume in drive C has no label.
Volume Serial Number is 3031-6CBE
Directory of C:IBMWebSphereLiberty8555_OSGIusrserversserver
05/08/2015 04:03 PM 98,004,525 server.zip
1 File(s) 98,004,525 bytes
0 Dir(s) 8,851,329,024 bytes free
C:IBMWebSphereLiberty8555_OSGIin>
Docker support
To ease testing and development cycles, you can also run your application using a pre-built Docker image containing IBM WebSphere Application Server for Developers V8.5.5 Liberty profile and an IBM JAVA Runtime Environment 7.1 in the Docker Hub. This means that you can get the Liberty profile Docker image environment quickly and run your own applications in there.
For information about Docker Hub, see the following website:
For information about Liberty profile Docker support, see the following website:
In short, to set your Docker Liberty profile environment, you need to do the following:
1. Set your Docker environment. For information about how to do that on your system, see the following website:
2. Pull your Liberty profile image using a Docker command, such as in Example 9-14.
Example 9-14 Running a WebSphere Liberty image in Docker
docker pull websphere-liberty
Pulling repository websphere-liberty
c659cb20283c: Download complete
e9e06b06e14c: Download complete
a82efea989f9: Download complete
37bea4ee0c81: Download complete
07f8e8c5e660: Download complete
1982456d9ebb: Download complete
068e3636b930: Download complete
16b920ee3a3f: Download complete
2508d7b16997: Download complete
0d361e23268a: Download complete
d6f640fd2033: Download complete
031348e20192: Download complete
71dcc2627667: Download complete
161847a85d6c: Download complete
f5fa021c4927: Download complete
3e165babb523: Download complete
a8a7133801c6: Download complete
c2a2ffe2d254: Download complete
3ce88d18a79e: Download complete
3c650dabf41a: Download complete
6681ce2f90c0: Download complete
9cc0db580156: Download complete
e1972175e2d4: Download complete
Status: Image is up to date for websphere-liberty:latest
3. Publish your application to your Docker Liberty profile environment by using a Docker command such as in Example 9-15 on page 247. This command uses the dropins folder of the Liberty profile server to deploy the application. For more information about the dropins directory, see 1.4.1, “Quick start using dropins” on page 28.
Example 9-15 Running an application in a WebSphere Liberty Docker container
docker run -d -e LICENSE=accept -p 80:9080 -v /tmp/myApp.war:/opt/ibm/wlp/usr/servers/defaultServer/dropins/myApp.war websphere-liberty
For an example on running an application in a WebSphere Liberty profile of a Docker container, read section 3.3, “Testing with a WebSphere Liberty Docker container” in Configuring and Deploying Open Source with WebSphere Application Server Liberty Profile, SG24-8194.
A Liberty product extension is a set of directories and files that have a layout similar to the Liberty product installation but are placed in your own installation location. It can contain the same types that are present in the Liberty product, such as feature and command-line scripts.
The function in a product extension can be fully integrated into the Liberty runtime and WebSphere developer tools. Because it uses the extensible Liberty architecture, it also integrates into future tools that are written to use that extensibility.
A product extension is identified to the Liberty run time through placement of a properties file in the Liberty installation. The name of the properties file is used as the product extension. For convenient development of features, there is a built-in user extension location in the Liberty installation structure: the usr/extension directory. You can install your features to that location for easy testing before you package them into your product extension. This is the location that the WebSphere developer tools use for feature installation.
When you design product extensions, there are many aspects that you might want to consider beyond simple function. These design principles are applied to the Liberty product features to keep the servers highly compassable and simple to use. Those design principles are covered in the following sections.
Allowing the user to compose their server
It is a core design principle of the Liberty profile that the user should select which features are in their server. This allows the user to control at a fine-grained level the exact services that are available. There is intentionally no support for profile augmentation, so when your feature is installed into an existing Liberty profile, it is not used by any servers unless the user explicitly adds the feature to the server configuration.
If you want to provide a way for your feature to be used without being manually added to the server configuration, you can provide a server template in the template servers directory of your product extension. This approach also allows you to provide a predefined custom configuration in addition to the feature itself. You can direct your users to specify your template on the server create command or you can provide your own command script in your extension bin directory that wraps the server create command and specifies your template, as shown in Example 9-16.
Example 9-16 Wrapping the server create command
server create --template=<extension-name>:<template-name>
Although this might be a convenient way to allow simple creation of working servers, it should not be used in place of providing useful configuration defaults in your features through metatype. Keeping the default values inside your feature allows you to adjust them in service or future releases. There is no support for modifying existing server.xml configuration files. These files are considered to be user-owned files and the Liberty profile does not change them.
For more information about Liberty profile product extensions, see 1.5, “Product extensions” on page 30.
Embedding the Liberty profile server in your applications
You can use the System Programming Interfaces (SPIs) that are provided by the Liberty profile to configure, control, and monitor a Liberty profile server in your applications.
The Liberty profile provides the following two SPIs to start or stop a Liberty profile server:
com.ibm.wsspi.kernel.embeddable.Server
com.ibm.wsspi.kernel.embeddable.ServerBuilder
Use a Future object to store the result of a start or stop operation. The return codes that are used by embedded operations are the same as the return codes used by the server command. Additionally, you can receive asynchronous notifications when the server is starting, has started, or has stopped by creating your own class that implements the com.ibm.wsspi.kernel.embeddable.ServerEventListener interface.
To include your Liberty profile server within your application, you must follow these steps:
1. Add to the class path the ws-server.jar file, which is in the ${wlp.install.dir}/bin/tools directory of the Liberty profile installation.
2. Specify the name of your target server.
 
Notes:
Environment variables are not checked and the jvm.options and server.env files are not read.
Management of the JVM and environment is assumed to be managed by the caller.
Configure the ws-javaagent.jar file with the -javaagent JVM option. The ws-javaagent.jar file is in the ${wlp.install.dir}/bin/tools directory of the Liberty profile installation. You are advised to configure the ws-javaagent.jar file, but it is not mandatory unless you use capabilities of the server that require it, such as monitoring or trace. If you contact IBM support, you might need to provide trace, and if so, you must start the server with the ws-javaagent.jar file, even if you do not normally use it.
For more information about procedure to embed your Liberty profile server into your applications, see the following website:
All configuration is specified in the server.xml file
Almost all configuration for a server can be specified in the server.xml or other included configuration files. One exception is the case where properties must be set before server.xml processing. For example, JVM properties cannot be set in server.xml and for those you can use the bootstrap.properties or jvm.options files. Another exception is the case where a public specification requires that the configuration be contained in a specific file. Specifying configuration in the server.xml or included files allows an ecosystem of commands and tools to be built on those files.
By receiving your configuration from the server.xml file, you benefit from the following capabilities:
Automatic parsing and injection of your configuration properties
Reinjection every time the property values are updated
Inclusion of your configuration in the generated schema that is used by the WebSphere developer tools and any future graphical user interfaces
Management of configuration files by the Liberty run time
It also benefits your users by allowing them to keep all of their server configurations in a single file or set of files.
Keeping it small and fast
Keep your dependency stack as short as possible. Defer as much of your initialization processing as possible. For example, you can use OSGi Declarative Services to delay loading of your service implementation classes until they are used.
Dynamic behavior
Features should be able to stop and restart independent of the server restarting and independent of each other. This consideration relies on correct cleanup on shutdown and the dynamic management of references to services in other features. Your features should react dynamically to configuration updates. This dramatically reduces the need for servers to be restarted, especially during application development. It also greatly increases usability.
Simple migration
It should be painless for users to apply service and product upgrades. Some design points that help to achieve that goal are included in the following list:
No migration is required for configuration; all configuration remains compatible with earlier versions.
Longer toleration of Java versions.
Clear separation of product and user files and internal and external function.
Feature evolution is strictly compatible with earlier versions. The versions in feature names provide a way to handle incompatibilities in upgrades by providing a new feature version with the new behavior but continuing to support the existing feature.
 
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset