diff --git a/posts/2024-06-28-liberty-user-feature-tutorial.adoc b/posts/2024-06-28-liberty-user-feature-tutorial.adoc new file mode 100644 index 000000000..93340de9b --- /dev/null +++ b/posts/2024-06-28-liberty-user-feature-tutorial.adoc @@ -0,0 +1,329 @@ +--- +layout: post +title: "How to package a library as an Open Liberty user feature" +# Do NOT change the categories section +categories: blog +author_picture: https://avatars3.githubusercontent.com/benjamin-confino +author_github: https://github.com/benjamin-confino +seo-title: How to package a library as an Open Liberty user feature - OpenLiberty.io +seo-description: A step by step guide on how to package a library as an OpenLiberty user feature. +blog_description: "A step by step guide on how to package a library as an OpenLiberty user feature." +open-graph-image: https://openliberty.io/img/twitter_card.jpg +open-graph-image-alt: Open Liberty Logo +--- += How to package a library as an Open Liberty user feature +Benjamin Confino +:imagesdir: / +:url-prefix: +:url-about: / + +== Learn how to integrate pre-existing software libraries into Open Liberty + +Recently, a customer asked me how to package their library as a user feature in Open Liberty so that applications could use it without packaging it directly. If you wish to do something similar, or have some other reason to create an Open Liberty user feature, this guide will walk you through doing so step by step. In this tutorial, you will learn the following skills: + + • How to import a maven artifact as a dependency and repackage it into an Open Liberty user feature. + • How to expose parts of your library as an API that can be imported + • How to expose parts of your library to CDI so it can be injected into user applications + +=== Prerequisites + +Maven version 3.8.6 or later + +=== Source code + +The source code for this post is in the link:https://github.com/benjamin-confino/liberty-user-feature-guide[liberty-user-feature-guide] repository, where you will find the following resources: + +- `finish` This directory contains the completed project you should have at the conclusion of this guide. You can use it as a reference. +- `start` This directory contains a skeleton you will modify to create the user feature. +- `scripts` You can ignore this directory. + +=== XML variables + +One of the trickiest things about packaging a liberty user feature with maven is ensuring variable names are constant across multiple XML files. To make this clearer, any variable that appears in two or more files will be set as a property in the root XML file. + +There is one exception in BOM/pom.xml which has to be a raw string, it is clearly labelled in the example `finish/bom/pom.xml` file. + +The feature names in an OpenLiberty `server.xml` file need to match an IBM-ShortName; in this case the one defined in the `esa/pom.xml` file. In the vast majority of cases, the `server.xml` is configured outside maven, so I have done the same and left labels. + +=== Example libraries + +For the purpose of this tutorial, Apache Commons is used as an example library that stands in for the library you wish to package as a user feature. + +=== Structure + +The project has the following structure: + +---- +root + ├── BOM + ├── demo + ├── ESA + └── integration +---- + +- `BOM` is the Bill of Materials. It tells Open Liberty which Maven artifacts are part of the feature. +- `demo` is a simple demo application. +- `integration` is an OSGi bundle containing new code written to integrate the pre-existing libraries into Open Liberty, in this case by exposing library classes to CDI. +- `ESA` is an OSGi Enterprise Subsystem Archive that packages up integration and the pre-existing libraries. + +Depending on your needs, the `integration` bundle might not be required. If you expect developers to use your library with plain old java syntax like `new LibraryClass()`, static accessors, or if it already has CDI producers or annotations, you might be able to ignore integration. + +=== Try what you will build + +The `finish` directory contains a completed version of this tutorial. Inside `finish`, have a look at `demo/src/main/java/example/app/TestServlet.java`. You will see that this class uses a class from our pre-existing library in two separate ways, once by injecting it via CDI and once as a plain old java class. + +Next have a look at `integration/src/main/java/com/ibm/example/cdi/CDIProducer.java` and you will see the `@Producer` method that turns a pre-existing class into an injectable bean. + +Lets compile it and give it a try, return to the `finish` directory and run the following commands: + +---- +mvn install +cd demo +mvn liberty:create +mvn liberty:prepare-feature +mvn liberty:install-feature +---- + +- `mvn liberty:create` creates a server locally. +- `mvn liberty:prepare-feature` populates your maven repository with details about Liberty features so the Liberty feature manager can install them. +- `mvn liberty:install-feature` instructs that feature manager to install our new feature. + +Have a quick look inside `target/open-liberty-integration.war`. You will see that it does not contain `Apache Commons`. Thanks to our integration code, `Apache Commons` is now provided by Liberty. + +Now use `mvn liberty:run` to start the server. Visit the http://localhost:8080/open-liberty-integration/ URL and you will see the two `ConstantInitializer` objects output Hello World. + + +=== Step one: Create the integration bundle + +The integration bundle will become an extension to Open Liberty, exposing new options to hosted applications. You can write a bundle that simply repackages an existing library as an Open Liberty feature. However, ours will go further by registering classes with the CDI subsystem so that applications can inject them. + +==== Write the Java code + +Navigate to the `start/integration/src/main/java/com/ibm/example/cdi/` directory. You will see two packages: `internal` and `api`. When you are finished, the contents of `api` will be available to import into application code. The contents of `internal` will not be, even though they can affect application classes. + +It is unlikely that a real integration glue package will need to be exposed as an API. You will see a more realistic example of exposing a pre-existing API in the next section. + +`api` has one file: `ExampleQualifier.java`. This is a normal CDI qualifier that you can ignore. + +`internal` has two files: `CDIProducer.java` and `CDIIntegrationMetaData.java`. + + • `CDIIntegrationMetaData.java` will implement an Open Liberty SPI that can register new beans. + • `CDIProducer.java` will be the new bean that produces other beans after constructing the contained object. In a real feature, it might read configuration and construct the bean using a factory object or the builder pattern. + +Open `CDIProducer.java` and add a producer method by adding the following code: + +[source,java] +---- + public ConstantInitializer getConstantInitializer() + { + return new ConstantInitializer("Hello"); + } +---- + +This method will do everything you need to create and return a fully configured object. However, CDI will not yet be aware it should invoke this method without the proper annotations. Add the following: + + • `@Produces` - so CDI knows this method is a source of an injectable bean, the bean’s type will come from the method’s return type. + • `@Dependent` - This will be the scope of the bean. We are using `@Dependent` because ConstantInitializer’s only constructor needs a parameter to make it non-proxiable. + • `@ExampleQualifier` - We’re adding a qualifier to the bean only so we have an example of an API class. + +Finally, since `CDIProducer` is itself a bean, it needs a scope. As `CDIProducer` has no state, add `@ApplicationScoped` to the class. All together, `CDIProducer` should look like the following example: + +[source,java] +---- +package com.ibm.example.cdi.internal; + +import jakarta.enterprise.inject.Produces; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.context.Dependent; + +import org.apache.commons.lang3.concurrent.ConstantInitializer; + +import com.ibm.example.cdi.api.ExampleQualifier; +@ApplicationScoped +public class CDIProducer +{ + @Produces + @Dependent + @ExampleQualifier + public ConstantInitializer getConstantInitializer() + { + return new ConstantInitializer("Hello"); + } +} +---- + +Next, open the `CDIIntegrationMetaData.java` file. To complete this class, register it as an OSGi component so that Open Liberty will provide it to the CDI framework when it looks for its lists of extensions. And then we’ll have to register `CDIProducer` as a bean. + +Add `@Component(service = CDIExtensionMetadata.class, configurationPolicy = IGNORE)` and `implements CDIExtensionMetadata` to the class to make it an OSGi component. + +Then add the following method + +[source,java] +---- + public Set> getBeanClasses() { + return Set.of(CDIProducer.class); + } +---- + +Before proceeding to the next step, review the Javadoc for https://openliberty.io/docs/latest/reference/javadoc/spi/cdi-1.2.html[CDIExtensionMetadata]. + +It is also important to be aware that `getBeanClasses()` is a unique Open Liberty idiom. The normal way to add a new bean would be to make a class that implements `javax.enterprise.inject.spi.Extension` and register it via `META-INF/services`. + +If you wish to use `Extension` for compatibility with other Jakarta EE servers or because your integration requires the power of a full `Extension`, then `CDIExtensionMetadata` has a different method you can use for this purpose. If you want to register your extension via `META-INF/services` rather than ` CDIExtensionMetadata`, see the link:https://openliberty.io/docs/latest/reference/feature/bells-1.0.html[BELL feature] documentation. + +==== Write the pom.xml + +Open the `start/integration/pom.xml` file. + +The `pom.xml` already contains all the dependencies we need to compile and build an unconfigured Maven bundle plugin. That is the next step. + +The bundle needs a human readable ``, a machine readable ``, and we need to provide a list of packages to include in the bundle. + +Inside `` add the line `example.user.feature.human.name` and `example.user.feature.integration.machine.name`. + +[source,xml] +---- + + example.user.feature.integration.machine.name + +example.user.feature.human.name +---- + + +Also inside `` you will find the tag ``, populate it with the following code: + +[source,xml] +---- +${new.integration.code.api.package};version="1.0.0", +${new.integration.code.private.package};version="1.0.0" +---- + +These classes will not be registered correctly without a version number. + +The instructions section of `integration/pom.xml` should now look something like this: + +[source,xml] +---- + + + ${new.integration.code.api.package};version="1.0.0", + ${new.integration.code.private.package};version="1.0.0", + + + example.user.feature.integration.machine.name + + example.user.feature.human.name + 1.0.0 + +---- + +Going back to the parent `pom.xml`, set these properties: + +[source,xml] +---- +com.ibm.example.cdi.internal +com.ibm.example.cdi.api +---- + +=== Step two: Create the ESA + +Open Liberty features are packaged as an Enterprise Subsystem Archive (ESA). We will create one that includes both our new integration code and the pre-existing library. + +Open the `esa/pom.xml` file. + +The first thing we need to do is ensure our ESA will have a `manifest.mf` file. Set `true` in the `` section of the `esa-maven-plugin`. + +Now, in instructions we will set a subystem symbolic name `example.user.feature.esa.machine.name;visibility:=public`. Setting the visibility to `public` is required. + +We will also need an IBM shortname. Add `${feature.name}` inside `instructions`. Then, in the `properties` section of the root `pom.xml` file, set `${feature.name}` to `example-feature-1.0` . + +Finally, in `esa/pom.xml`, add the following code under ``. + +[source,xml] +---- +${pre.existing.library.package};version="3.14.0", +${new.integration.code.api.package};version="1.0.0" +---- + +This will make those two packages visible to applications at runtime. + +When you finish, the `esa-maven-plugin` `` will be similar to the following example: + +[source,xml] +---- + + true + all + + + example.user.feature.esa.machine.name;visibility:=public + + IBM + 2 + ${feature.name} + osgi.subsystem.feature + 1.0.0 + + ${pre.existing.library.package};version="3.14.0", + ${new.integration.code.api.package};version="1.0.0" + + + +---- + + +The ESA is now complete. But there is one final step, set `${pre.existing.library.package}` to `org.apache.commons.lang3.concurrent` by defining the property in the parent `pom.xml` file: + +[source.xml] +---- + + ... + org.apache.commons.lang3.concurrent + ... + +---- + +=== Step three: Create the Bill of Materials + +The `liberty-maven-plugin` requires a bill of materials to find and install features. In the real world, the Bill of Materials might be defined in the ESA `pom.xml` file, but this tutorial will keep them separate for clarity. + +Open the `bom/pom.xml` file and add the following dependency. + +[source.xml] +---- + + com.ibm.example.user.feature + + + liberty-feature + 1.0-SNAPSHOT + esa + provided + +---- + +=== Step four: Add your Liberty user feature to a Liberty server + +Go to `demo/src/liberty/server.xml` and add the following feature definition inside the `featureManager` element: + +[source,xml] +---- + + ... + usr:example-feature-1.0 + +---- + +`usr:` is prepended for all user features, and the second part of the feature name is the `IBM-ShortName` for the feature. + +Naturally, a liberty `server.xml` cannot read properties from a `pom.xml`, so we have to put `usr:example-feature-1.0` in as a raw string. + +=== Gotchas + +Here are a few non-obvious risks and things to be aware off. + +- The use of injection for libraries is limited. You can take classes found in the library and inject them into application classes, but you can't take classes provided by Open Liberty itself, or application code, and inject them into your library’s classes. Incidentally, the way to get a Config object from MicroProfile Config in OpenLiberty without injection is `org.eclipse.microprofile.config.ConfigProvider.getConfig(Thread.currentThread().getContextClassLoader());` + +- The `` tag in the `integration/pom.xml` file controls what packages are included in the bundle. Make sure you get everything you need. + +- If a package isn’t listed as `IBM-API-PACKAGE`, applications will not be able to access classes from that package. This means trying to `@Inject` those classes will fail. diff --git a/posts/2024-08-15-24.0.0.8.adoc b/posts/2024-08-15-24.0.0.8.adoc new file mode 100644 index 000000000..aa5e8cbb9 --- /dev/null +++ b/posts/2024-08-15-24.0.0.8.adoc @@ -0,0 +1,351 @@ +--- +layout: post +title: "An introduction to using Versionless Features with Open Liberty" +# Do NOT change the categories section +categories: blog +author_picture: https://avatars3.githubusercontent.com/hlhoots +author_github: https://github.com/hlhoots +seo-title: TITLE - OpenLiberty.io +seo-description: Learn how to utlize Versionless Features in your Open Liberty application configurations. +blog_description: "Learn how to utlize Versionless Features in your Open Liberty application configurations." +open-graph-image: https://openliberty.io/img/twitter_card.jpg +open-graph-image-alt: Open Liberty Logo +additional_authors: +- name: Thomas Bitonti + github: https://github.com/tbitonti + image: https://avatars0.githubusercontent.com/tbitonti +- name: Ricky Herget + github: https://github.com/rsherget + image: https://avatars0.githubusercontent.com/rsherget +--- += Working with Versionless Features +Harry Hoots +:imagesdir: / +:url-prefix: +:url-about: / +//Blank line here is necessary before starting the body of the post. + +// // // // // // // // +// In the preceding section: +// Do not insert any blank lines between any of the lines. +// +// "open-graph-image" is set to OL logo. Whenever possible update this to a more appropriate/specific image (for example if present an image that is being used in the post). +// However, it can be left empty which will set it to the default +// +// "open-graph-image-alt" is a description of what is in the image (not a caption). When changing "open-graph-image" to +// a custom picture, you must provide a custom string for "open-graph-image-alt". +// +// Replace TITLE with the blog post title +// +// Replace SECOND_AUTHOR_NAME with the name of the second author. +// Replace SECOND_GITHUB_USERNAME with the GitHub user name of the second author. +// Replace THIRD_AUTHOR_NAME with the name of the third author. And so on for fourth, fifth, etc authors. +// Replace THIRD_GITHUB_USERNAME with the GitHub user name of the third author. And so on for fourth, fifth, etc authors. +// +// Replace AUTHOR_NAME with your name as first author. +// Replace GITHUB_USERNAME with your GitHub username eg: lauracowen +// Replace DESCRIPTION with a short summary (~60 words) of the release (a more succinct version of the first paragraph of the post). +// +// Replace AUTHOR_NAME with your name as you'd like it to be displayed, eg: Laura Cowen +// +// Example post: 2020-02-12-faster-startup-Java-applications-criu.adoc +// +// If adding image into the post add : +// ------------------------- +// [.img_border_light] +// image::img/blog/FILE_NAME[IMAGE CAPTION ,width=70%,align="center"] +// ------------------------- +// "[.img_border_light]" = This adds a faint grey border around the image to make its edges sharper. Use it around +// screenshots but not around diagrams. Then double check how it looks. +// There is also a "[.img_border_dark]" class which tends to work best with screenshots that are taken on dark backgrounds. +// Once again make sure to double check how it looks +// Change "FILE_NAME" to the name of the image file. Also make sure to put the image into the right folder which is: img/blog +// change the "IMAGE CAPTION" to a couple words of what the image is +// // // // // // // // + +== Which Feature do I use? + +With the 24.0.0.8 release, Open Liberty adds a new function called Versionless Features. + +As you may well know, Open Liberty is a composable server in which you only configure necessary features at the specific versions that your application needs. This composable design pattern minimizes the features used by the server, keeping startup times short and memory footprints low. But, this adds a burden on the developer: Picking feature versions. Developers can struggle to determine which version of a feature is compatible with the other features utilized by their application. Determining the correct version typically requires that the developer experiment, plugging in different versions of features until they find one that works, or requires that they dig deep into feature documentation. Either way, it’s not an ideal experience, and Versionless Features are here to make life easier. + +== What are Versionless Features? And why do I need a Platform? + +Versionless features are platform-specific generic features which have no version number. When you use versionless features, the Open Liberty feature resolver finds the versions of those generic features which are compatible with your other configured features. + +Other than having no version number, versionless features are used in the server configuration the same as versioned features are used. Except, there is one added requirement: At least one platform must be specified. + +(*) More precisely: Two platforms are currently available: javaee/jakartaee and microProfile. When a versionless javaee/jakartaee feature is used, a javaee/jakarta platform must be specified. When a versionless microProfile feature is used, a microProfile platform must be specified. + +A platform is most often specified using a platform element. Platforms elements are new elements of the server configuration which are placed alongside feature elements. + +Platform elements and feature elements may be placed in any order. The order of these elements does not affect feature resolution. However, our suggestion is that platform elements should be placed before feature elements. + +In addition to platform elements, there are two ways of specifying a platform. First, the platform may be determined by a versioned feature which is associated with a particular platform version. Second, the platform may be specified using the environment variable #PREFERRED_PLATFORM_VERSIONS#. + +Versionless features are available for almost all versioned features which are associated with a platform. For example, because the Servlet specification is associated with javaee/jakartaee, a versionless servlet feature is available. + +(**) To ensure that the choice of version for a versionless feature is meaningful and correct, only those features which have a clear association with an API Platform are provided as versionless features. Features which don’t have a clear association with an API Platform do not have a versionless feature. Also, there are features which are associated with an API Platform but which are usually not used. These features are not provided as versionless features. + +For example, because link:https://openliberty.io/docs/latest/reference/feature/restConnector-2.0.html[restConnector-2.0] is not clearly associated with either MicroProfile or JakartaEE/JavaEE, there is no restConnector versionless feature. Similarly, springboot features do not have a clear association with an API Platform. No springboot versionless feature exists for #springboot-1.5#, #springboot-2.0#, and #springboot-3.0#. + +One may notice that platforms and convenience features have the same names. That sharing of names is deliberate. Both have the same association with a specific technology at a specific specification level. The difference is in how the association is used. Convenience features bring in all of the features related to a platform, where-as platforms determine what versions of versionless features are to be used. That is, a platform, by itself, brings in no features. A platform plus a versionless feature brings in a compatible version of the versionless feature. + +Read more about link:https://openliberty.io/docs/latest/reference/feature/feature-overview.html#conv[platform convenience features]. + +== Best practices: + +As a new *best practice*, when specifying features within a server configuration, specify a platform elements based on the platform and platform version that of applications which are to be run by the server, and specify as versionless features only those features which are needed by the applications. + +(Up to 2 platform elements may be specified, one for MicroProfile, another for JakartaEE/JavaEE.) + +For example, this configuration uses versionless features with the #MicroProfile-5.0# platform: +``` + + + microProfile-5.0 + mpHealth + mpMetrics + +``` +This configuration uses versionless features with #javaee-8.0#: +``` + + + javaee-8.0 + servlet + jpa + jaxrs + +``` + +== Platforms and platform versions + +As of Open Liberty version 24.0.0.8, two platforms are available: jakartaee/javaee, and microProfile. Altogether, these platform versions are available. (The actual presence a particular platform versions depends on the particular server package.) + +=== Platform versions: + +==== JakartaEE/JavaEE + +* javaee-6.0 +* javaee-7.0 +* javaee-8.0 +* jakartaee-9.1 +* jakartaee-10.0 + +==== MicroProfile + +* microProfile-1.2 +* microProfile-1.3 +* microProfile-1.4 +* microProfile-2.0 +* microProfile-2.1 +* microProfile-2.2 +* microProfile-3.0 +* microProfile-3.2 +* microProfile-3.3 +* microProfile-4.0 +* microProfile-4.1 +* microProfile-5.0 +* microProfile-6.0 +* microProfile-6.1 + +== Versionless features + +These versionless features are available. Many are available with two names, since most of these were renamed within the transition from javaee to jakartaee. When two names are given, the format is jakartaee-name / javaee-name. + +* jakartaee/javaee versionless features: +* appAuthentication / jaspic +* appAuthorization / jacc +* appClientSupport +* appSecurity +* batch +* beanValidation +* cdi +* concurrent +* connectors / jca +* connectorsInboundSecurity / jcainboundsecurity +* data +* enterpriseBeans / ejb +* enterpriseBeansHome / ejbhome +* enterpriseBeansLite / ejblite +* expressionLanguage / el +* enterpriseBeansPersistentTimer / ejbpersistenttimer +* enterpriseBeansRemote / ejbremote +* faces / jsf +* j2eeManagement +* mail / javaMail +* jdbc +* jsonb +* jsonp +* managedBeans +* mdb +* messaging / jms +* messagingClient / wasjmsclient +* messagingSecurity / wasjmssecurity +* messagingServer / wasjmsserver +* pages / jsp +* persistence / jpa +* restfulWS / jaxrs +* restfulWSClient / jaxrsclient +* servlet +* websocket +* xmlBinding / jaxb +* xmlWS / jaxws +* microProfile versionless features: +* mpConfig +* mpFaultTolerance +* mpHealth +* mpJwt +* mpMetrics +* mpOpenAPI +* mpOpenTracing +* mpRestClient +* mpTelemetry + +==== Non-versionless features: + +Not all public features are available as versionless features. + +These features have an association with jakartaee/javaee, but are not available as versionless features: + +* facesContainer / jsfcontainer +* persistenceContainer / jpacontainer + +facesContainer and persistenceContainer enable third party faces and persistence implementations, and are not used unless a third party implementation is being used. + +These features are weakly associated with jakartaee/javaee, but are not available as versionless features: + +* distributedMap +* jndi +* jpaContainer +* json +* jwt +* monitor +* opentracing +* persistenceContainer +* restConnector +* ssl + +== Specifying Platforms + +Now that we’ve discussed Versionless Features and Platforms at a high level, let’s talk a little bit more in depth about the configuration options. + +As mentioned previously, there are 3 ways to specify the platform. + +1. In the server.xml with a platform element. + +Configuring platform elements in the server.xml file is the best practice. Simply add a ## element under the ## configuration, similar to the following: +``` + + + microProfile-6.1 + mpHealth + mpMetrics + +``` + +2. In the server.xml with a versioned feature instead of a platform. + +In many cases, a platform may be determined from versioned features. Sometimes, just one versioned feature is sufficient, however, and in particular for microProfile, more than one versioned feature may be needed. A Platform version will only be chosen when 1 or more versioned features defined have a single shared platform version. + +For example, because #mpHealth-3.0# is associated with #microProfile-4.0#, the following configurations are equivalent: + +===== A server configuration that uses a platform element: +``` + + + microProfile-4.0 + mpHealth + mpMetrics + mpConfig>/feature> + +``` +===== A server configuration that uses a versioned feature: +``` + + + mpHealth-3.0 + mpMetrics + mpConfig>/feature> + +``` +//Unsure if we want to get this technical about it, feel free to delete the below sentences. + +The feature mpHealth is part of MicroProfile-4.0, and no other MicroProfile version, so we can determine the platform version with just this feature. mpMetrics and mpConfig will both resolve to their versions that are part of MicroProfile-4.0. mpMetrics will resolve to #mpMetrics-3.0# and mpConfig will resolve to #mpConfig-2.0#. + +3. In an environment variable. + +Platforms may be specified using environment variable #PREFERRED_PLATFORM_VERSIONS#. This variable can be specified in two locations: + +a. In the #server.env# configuration file. + +``` +# Define the Platform selector values +PREFERRED_PLATFORM_VERSIONS="microProfile-6.0, jakartaee-10" +``` + +b. In the shell environment +``` +$ export PREFERRED_PLATFORM_VERSIONS="microProfile-6.0, jakartaee-10" +``` + +== Server packaging command + +The ‘server package’ command is a command line application that can be utilized by developers to package up their application and all required server related components after development is completed. This is very useful when moving the application to a new environment or moving it to a container image for the Cloud. + +As mentioned above the *best practice* is to use the server.xml to define your Platform selector. If you do utilize the #PREFERRED_PLATFORM_VERSIONS# environment variable its also a best practice to specify that value in the ‘server.env’ configruation file vs in the actual environment shell. If you utilize the #PREFERRED_PLATFORM_VERSIONS# variable as a true environment variable in the shell outside of the ‘server.env’ file, and you use the ‘server package’ command the variable will not be retained during packaging. + +If this scenario occurs, the ‘server package’ command will issue a warning as follows: + +``` +CWWKE0969W: A manual PREFERRED_PLATFORM_VERSION environment variable was specified during server packaging. +``` + +In the new environment where the packaged server will be executed, the user would have to re-create the PREFERRED_PLATFORM_VERSION with the same platform values. + +== Download packages + +Versionless Features will be included in the various link:https://openliberty.io/start/#downloads-pkg[download packages]. As an example, the microProfile-4 package currently contains the following features: +``` +microProfile-4.0 +microProfile-4.1 +localConnector-1.0 +``` +As an update to include Versionless Features, the following will be added to the MicroProfile-4 package: +``` +appSecurity +cdi +el +jaxrs +jaxrsClient +jndi +jsonb +jsonp +mpJwt +mpFaultTolerance +mpOpenAPI +mpOpenTracing +mpRestClient +mpHealth +mpMetrics +mpConfig +servlet +``` +Other existing packages will follow in similar fashion by adding the versionless features corresponding to the included versioned features. + +== We welcome your feedback + +We hope that versionless features gives you a better developer experience with choosing Open Liberty features. Please let us know what you think on link:https://groups.io/g/openliberty[our mailing list]. If you hit a problem, link:https://stackoverflow.com/questions/tagged/open-liberty[post a question on StackOverflow]. If you hit a bug, link:https://github.com/OpenLiberty/open-liberty/issues[please raise an issue]. + + +// // // // // // // // +// LINKS +// +// OpenLiberty.io site links: +// link:{url-prefix}/guides/microprofile-rest-client.html[Consuming RESTful Java microservices] +// +// Off-site links: +// link:https://openapi-generator.tech/docs/installation#jar[Download Instructions] +// +// // // // // // // //