+ that uniquely identifies the component (e.g.
-# +open_jdk=1.7.0_40+). Otherwise, +nil+.
-def detect
-
-# Modifies the application's file system. The component is expected to transform the application's file system in
-# whatever way is necessary (e.g. downloading files or creating symbolic links) to support the function of the
-# component. Status output written to +STDOUT+ is expected as part of this invocation.
-#
-# @return [void]
-def compile
-
-# Modifies the application's runtime configuration. The component is expected to transform members of the +context+
-# (e.g. +@java_home+, +@java_opts+, etc.) in whatever way is necessary to support the function of the component.
-#
-# Container components are also expected to create the command required to run the application. These components
-# are expected to read the +context+ values and take them into account when creating the command.
-#
-# @return [void, String] components other than containers are not expected to return any value. Container
-# components are expected to return the command required to run the application.
-def release
-```
-
-## Exposed Instance Variables
-
-| Name | Type
-| ---- | ----
-| `@application` | [`JavaBuildpack::Component::Application`][]
-| `@component_name` | `String`
-| `@configuration` | `Hash`
-| `@droplet` | [`JavaBuildpack::Component::Droplet`][]
-
-## Helper Methods
-
-```ruby
-# Downloads an item with the given name and version from the given URI, then yields the resultant file to the given
-# block.
-#
-# @param [JavaBuildpack::Util::TokenizedVersion] version
-# @param [String] uri
-# @param [String] name an optional name for the download. Defaults to +@component_name+.
-# @return [void]
-def download(version, uri, name = @component_name, &block)
-
-# Downloads a given JAR file and stores it.
-#
-# @param [String] version the version of the download
-# @param [String] uri the uri of the download
-# @param [String] jar_name the name to save the jar as
-# @param [Pathname] target_directory the directory to store the JAR file in. Defaults to the component's sandbox.
-# @param [String] name an optional name for the download. Defaults to +@component_name+.
-def download_jar(version, uri, jar_name, target_directory = @droplet.sandbox, name = @component_name)
-
-# Downloads a given TAR file and expands it.
-#
-# @param [String] version the version of the download
-# @param [String] uri the uri of the download
-# @param [Pathname] target_directory the directory to expand the TAR file to. Defaults to the component's sandbox.
-# @param [String] name an optional name for the download and expansion. Defaults to +@component_name+.
-def download_tar(version, uri, target_directory = @droplet.sandbox, name = @component_name)
-
-# Downloads a given ZIP file and expands it.
-#
-# @param [Boolean] strip_top_level whether to strip the top-level directory when expanding. Defaults to +true+.
-# @param [Pathname] target_directory the directory to expand the ZIP file to. Defaults to the component's sandbox.
-# @param [String] name an optional name for the download. Defaults to +@component_name+.
-def download_zip(version, uri, strip_top_level = true, target_directory = @droplet.sandbox, name = @component_name)
-
-# Wrap the execution of a block with timing information
-#
-# @param [String] caption the caption to print when timing starts
-def with_timing(caption)
-```
-
-[`JavaBuildpack::Component::Application`]: extending-application.md
-[`JavaBuildpack::Component::Droplet`]: extending-droplet.md
diff --git a/docs/extending-caches.md b/docs/extending-caches.md
deleted file mode 100644
index 7811e3df74..0000000000
--- a/docs/extending-caches.md
+++ /dev/null
@@ -1,86 +0,0 @@
-# Caches
-Many components will want to cache large files that are downloaded for applications. The buildpack provides a cache abstraction to encapsulate this caching behavior. The cache abstraction is comprised of three cache types each with the same signature.
-
-```ruby
-# Retrieves an item from the cache. Retrieval of the item uses the following algorithm:
-#
-# 1. Obtain an exclusive lock based on the URI of the item. This allows concurrency for different items, but not for
-# the same item.
-# 2. If the the cached item does not exist, download from +uri+ and cache it, its +Etag+, and its +Last-Modified+
-# values if they exist.
-# 3. If the cached file does exist, and the original download had an +Etag+ or a +Last-Modified+ value, attempt to
-# download from +uri+ again. If the result is +304+ (+Not-Modified+), then proceed without changing the cached
-# item. If it is anything else, overwrite the cached file and its +Etag+ and +Last-Modified+ values if they exist.
-# 4. Downgrade the lock to a shared lock as no further mutation of the cache is possible. This allows concurrency for
-# read access of the item.
-# 5. Yield the cached file (opened read-only) to the passed in block. Once the block is complete, the file is closed
-# and the lock is released.
-#
-# @param [String] uri the uri to download if the item is not already in the cache. Also used in the case where the
-# item is already in the cache, to validate that the item is up to date
-# @yieldparam [File] file the file representing the cached item. In order to ensure that the file is not changed or
-# deleted while it is being used, the cached item can only be accessed as part of a block.
-# @return [void]
-def get(uri)
-
-# Remove an item from the cache
-#
-# @param [String] uri the URI of the item to remove
-# @return [void]
-def evict(uri)
-```
-
-Usage of a cache might look like the following:
-
-```ruby
-JavaBuildpack::Util::DownloadCache.new().get(uri) do |file|
- YAML.load_file(file)
-end
-```
-
-## Configuration
-For general information on configuring the buildpack, refer to [Configuration and Extension][].
-
-Caching can be configured by modifying the [`config/cache.yml`][] file.
-
-| Name | Description
-| ---- | -----------
-| `remote_downloads` | This property can take the value `enabled` or `disabled`. The default value of `enabled` means that the buildpack will check the internet connection and remember the result for the remainder of the buildpack invocation. If the internet is available, it will then be used to download files. If the internet is not available, cache will be consulted instead.
Alternatively, the property may be set to `disabled` which avoids the check for an internet connection, does not attempt downloads, and consults the cache instead.
-
-## `JavaBuildpack::Util::Cache::DownloadCache`
-The [`DownloadCache`][] is the most generic of the three caches. It allows you to create a cache that persists files any that write access is available. The constructor signature looks the following:
-
-```ruby
-# Creates an instance of the cache that is backed by the filesystem rooted at +cache_root+
-#
-# @param [String] cache_root the filesystem root for downloaded files to be cached in
-def initialize(cache_root = Dir.tmpdir)
-```
-
-## `JavaBuildpack::Util::Cache::ApplicationCache`
-The [`ApplicationCache`][] is a cache that persists files into the application cache passed to the `compile` script. It examines `ARGV[1]` for the cache location and configures itself accordingly.
-
-```ruby
-# Creates an instance that is configured to use the application cache. The application cache location is defined by
-# the second argument (ARGV[1]) to the +compile+ script.
-#
-# @raise if the second argument (ARGV[1]) to the +compile+ script is +nil+
-def initialize
-```
-
-## `JavaBuildpack::Util::Cache::GlobalCache`
-The [`GlobalCache`][] is a cache that persists files into the global cache passed to all scripts. It examines `ENV['BUILDPACK_CACHE']` for the cache location and configures itself accordingly.
-
-```ruby
-# Creates an instance that is configured to use the global cache. The global cache location is defined by the
-# +BUILDPACK_CACHE+ environment variable
-#
-# @raise if the +BUILDPACK_CACHE+ environment variable is +nil+
-def initialize
-```
-
-[`ApplicationCache`]: ../lib/java_buildpack/util/cache/application_cache.rb
-[`config/cache.yml`]: ../config/cache.yml
-[`DownloadCache`]: ../lib/java_buildpack/util/cache/download_cache.rb
-[`GlobalCache`]: ../lib/java_buildpack/util/cache/global_cache.rb
-[Configuration and Extension]: ../README.md#configuration-and-extension
diff --git a/docs/extending-droplet.md b/docs/extending-droplet.md
deleted file mode 100644
index 798bfa0dbe..0000000000
--- a/docs/extending-droplet.md
+++ /dev/null
@@ -1,122 +0,0 @@
-# `JavaBuildpack::Component::Droplet`
-The `Droplet` is a read-write abstraction that exposes information about the Cloud Foundry droplet that is being created. In Cloud Foundry terminology, a droplet encapsulates the filesystem and runtime configuration that will be run. Each of these things is exposed by the `Droplet` abstraction.
-
-```ruby
-# @!attribute [r] additional_libraries
-# @return [AdditionalLibraries] the shared +AdditionalLibraries+ instance for all components
-attr_reader :additional_libraries
-
-# @!attribute [r] component_id
-# @return [String] the id of component using this droplet
-attr_reader :component_id
-
-# @!attribute [r] java_home
-# @return [ImmutableJavaHome, MutableJavaHome] the shared +JavaHome+ instance for all components. If the
-# component using this instance is a jre, then this will be an
-# instance of +MutableJavaHome+. Otherwise it will be an instance of
-# +ImmutableJavaHome+.
-attr_reader :java_home
-
-# @!attribute [r] java_opts
-# @return [JavaOpts] the shared +JavaOpts+ instance for all components
-attr_reader :java_opts
-
-# @!attribute [r] root
-# @return [JavaBuildpack::Util::FilteringPathname] the root of the droplet's fileystem filtered so that it
-# excludes files in the sandboxes of other components
-attr_reader :root
-
-# @!attribute [r] sandbox
-# @return [Pathname] the root of the component's sandbox
-attr_reader :sandbox
-
-# Copy resources from a components resources directory to a directory
-#
-# @param [Pathname] target_directory the directory to copy to. Default to a component's +sandbox+
-def copy_resources(target_directory = @sandbox)
-```
-
-## `additional_libraries`
-A helper type (`JavaBuildpack::Component::AdditionalLibraries`) that enables the addition of JARs to the classpath of the running droplet.
-
-```ruby
-# Returns the contents of the collection as a classpath formatted as +-cp :+
-#
-# @return [String] the contents of the collection as a classpath
-def as_classpath
-
-# Symlink the contents of the collection to a destination directory.
-#
-# @param [Pathname] destination the destination to link to
-def link_to(destination)
-```
-
-## `component_id`
-The id of the component, as determined by the buildpack. This is used in various locations and is exposed to ensure uniformity of the value.
-
-## `java_home`
-One of two helper types (`JavaBuildpack::Component::ImmutableJavaHome`, `JavaBuildpack::Component::MutableJavaHome`) that enables the mutation and retrieval of the droplet's `JAVA_HOME`. Components that are JREs will be given the `MutableJavaHome` in order to set the value. All other components will be given the `ImmutableJavaHome` in order to retrieve the value.
-
-```ruby
-# Returns the path of +JAVA_HOME+ as an environment variable formatted as +JAVA_HOME="$PWD/"+
-#
-# @return [String] the path of +JAVA_HOME+ as an environment variable
-def as_env_var
-
-# Execute a block with the +JAVA_HOME+ environment variable set
-#
-# @yield yields to block with the +JAVA_HOME+ environment variable set
-def do_with
-
-# @return [String] the root of the droplet's +JAVA_HOME+
-def root
-
-# Sets the root of the droplet's +JAVA_HOME+
-#
-# @param [Pathname] value the root of the droplet's +JAVA_HOME+
-def root=(value)
-```
-
-## `java_opts`
-A helper type (`JavaBuildpack::Component::JavaOpts`) that enables the addition of values to +JAVA_OPTS+. The `add_javaagent`, `add_system_property`, and `add_option` method all inspect that value to determine if it is a `Pathname`. If it is, the value is converted so that it is relative to the root of the droplet.
-
-```ruby
-# Adds a +javaagent+ entry to the +JAVA_OPTS+. Prepends +$PWD+ to the path (relative to the droplet root) to
-# ensure that the path is always accurate.
-#
-# @param [Pathname] path the path to the +javaagent+ JAR
-# @return [JavaOpts] +self+ for chaining
-def add_javaagent(path)
-
-# Adds a system property to the +JAVA_OPTS+. Ensures that the key is prepended with +-D+. If the value is a
-# +Pathname+, then prepends +$PWD+ to the path (relative to the droplet root) to ensure that the path is always
-# accurate. Otherwise, uses the value as-is.
-#
-# @param [String] key the key of the system property
-# @param [Pathname, String] value the value of the system property
-# @return [JavaOpts] +self+ for chaining
-def add_system_property(key, value)
-
-# Adds an option to the +JAVA_OPTS+. Nothing is prepended to the key. If the value is a +Pathname+, then prepends
-# +$PWD+ to the path (relative to the droplet root) to ensure that the path is always accurate. Otherwise, uses
-# the value as-is.
-#
-# @param [String] key the key of the option
-# @param [Pathname, String] value the value of the system property
-# @return [JavaOpts] +self+ for chaining
-def add_option(key, value)
-
-# Returns the contents as an environment variable formatted as +JAVA_OPTS=" "+
-#
-# @return [String] the contents as an environment variable
-def as_env_var
-```
-
-## `root`
-The root of the filesystem for the droplet. This is a `JavaBuildpack::Util::FilteringPathname` to ensure that this view of the filesystem includes _only_ the users's code and the files in the component's sandbox. It can be safely assumed that other `Pathname`s based on this `root` will accurately reflect filesystem attributes for those files.
-
-## `sandbox`
-The root of the filesystem for the component's sandbox. The sandbox is a portion of the filesystem that a component can work in that is isolated from all other components. This is a `JavaBuildpack::Util::FilteringPathname` to ensure that this view of the filesystem includes _only_ the the component's sandbox. It can be safely assumed that other `Pathname`s based on this `sandbox` will accurately reflect filesystem attributes for those files.
-
-## `copy_resources()`
-Copy the contents of the component's resources directory if it exists. The components resources directory is found in the `/resources/`. This is typically used to overlay the contents of the resources directory onto a component's sandbox.
diff --git a/docs/extending-logging.md b/docs/extending-logging.md
deleted file mode 100644
index 055554f835..0000000000
--- a/docs/extending-logging.md
+++ /dev/null
@@ -1,37 +0,0 @@
-# Logging
-
-The Java buildpack logs all messages, regardless of severity to `/.java-buildpack.log`. It also logs messages to `$stderr`, filtered by a configured severity.
-
-If the buildpack fails with an exception, the exception message is logged with a log level of `ERROR` whereas the exception stack trace is logged with a log level of `DEBUG` to prevent users from seeing stack traces by default.
-
-## Sensitive Information in Logs
-The Java buildpack logs sensitive information, such as environment variables which may contain security credentials.
-
-_You should be careful not to expose this information inadvertently_, for example by posting standard error stream contents or the contents of `/.java-buildpack.log` to a public discussion list.
-
-## Logger Usage
-The `JavaBuildpack::Logging::LoggerFactory` class manages instances that meet the contract of the standard Ruby `Logger`. In normal usage, the `Buildpack` class configures the `LoggerFactory`. `Logger` instances are then retrieved for classes that require them:
-
-```ruby
-@logger = JavaBuildpack::Logging::LoggerFactory.get_logger DownloadCache
-```
-
-This logger is used like the standard Ruby logger and supports both parameter and block forms:
-
-```
-logger.info('success')
-logger.debug { "#{costly_method}" }
-```
-
-## Configuration
-For general information on configuring the buildpack, refer to [Configuration and Extension][].
-
-The console logging severity filter is set to `DEBUG`, `INFO`, `WARN`, `ERROR`, `FATAL` using the following strategies in descending priority:
-
-1. `$JBP_LOG_LEVEL` environment variable. This can be set using the `cf set-env JBP_LOG_LEVEL DEBUG` command.
-2. Ruby `--verbose` and `--debug` flags. Setting either of these is the equivalent of setting the log severity level to `DEBUG`.
-3. `default_log_level` value in [`config/logging.yml`][].
-4. Fallback to `INFO` if none of the above are set.
-
-[Configuration and Extension]: ../README.md#configuration-and-extension
-[`config/logging.yml`]: ../config/logging.yml
diff --git a/docs/extending-modular_component.md b/docs/extending-modular_component.md
deleted file mode 100644
index 8760e930a9..0000000000
--- a/docs/extending-modular_component.md
+++ /dev/null
@@ -1,43 +0,0 @@
-# `JavaBuildpack::Component::ModularComponent`
-This base class is recommended for use by any component that is sufficiently complex to need modularization. It enables a component to be composed of multiple "sub-components" and coordinates the component lifecycle across all of them.
-
-## Required Method Implementations
-
-```ruby
-# The command for this component
-#
-# @return [void, String] components other than containers are not expected to return any value. Container
-# components are expected to return the command required to run the application.
-def command
-
-# The modules that make up this component
-#
-# @param [Hash] context the context of the component
-# @return [Array] a collection of +BaseComponent+s that make up the modules of this component
-def modules(context)
-
-# Whether or not this component supports this application
-#
-# @return [Boolean] whether or not this component supports this application
-def supports?
-```
-
-## Exposed Instance Variables
-
-| Name | Type
-| ---- | ----
-| `@modules` | [`Array`][]
-
-
-## Helper Methods
-
-```ruby
-# Returns a copy of the context, but with a subset of the original configuration
-#
-# @param [Hash] context the original context of the component
-# @param [String] key the key to get a subset of the context from
-# @return [Hash] context a copy of the original context, but with a subset of the original configuration
-def sub_configuration_context(context, key)
-```
-
-[`Array`]: extending-base_component.md
diff --git a/docs/extending-repositories.md b/docs/extending-repositories.md
index c4829310a5..1ec21a6b93 100644
--- a/docs/extending-repositories.md
+++ b/docs/extending-repositories.md
@@ -22,15 +22,17 @@ An example filesystem might look like:
The main class used when dealing with a repository is [`JavaBuildpack::Repository::ConfiguredItem`][]. It provides a single method that is used to resolve a specific version and its URI.
```ruby
-# Finds an instance of the file based on the configuration.
+# Finds an instance of the file based on the configuration and wraps any exceptions
+# to identify the component.
#
+# @param [String] component_name the name of the component
# @param [Hash] configuration the configuration
# @option configuration [String] :repository_root the root directory of the repository
# @option configuration [String] :version the version of the file to resolve
# @param [Block, nil] version_validator an optional version validation block
-# @return [JavaBuildpack::Util::TokenizedVersion] the chosen version of the file
# @return [String] the URI of the chosen version of the file
-def find_item(configuration, &version_validator)
+# @return [JavaBuildpack::Util::TokenizedVersion] the chosen version of the file
+def find_item(component_name, configuration)
```
Usage of the class might look like the following:
@@ -52,19 +54,26 @@ end
| Variable | Description |
| -------- | ----------- |
-| `{default.repository.root}` | The common root for all repositories. Currently defaults to `http://download.pivotal.io.s3.amazonaws.com`.
-| `{platform}` | The platform that the application is running on. Currently detects `centos6`, `lucid`, `mountainlion`, and `precise`.
+| `{default.repository.root}` | The common root for all repositories. Currently defaults to `https://java-buildpack.cloudfoundry.org`.
+| `{platform}` | The platform that the application is running on. Currently detects `jammy`, etc.
| `{architecture}` | The architecture of the system as returned by Ruby. The value is typically one of `x86_64` or `x86`.
## Configuration
-For general information on configuring the buildpack, refer to [Configuration and Extension][].
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
-Repositories can be configured by modifying the [`config/repository.yml`][] file.
+Repositories can be configured by modifying the [`config/repository.yml`][] file in the buildpack fork.
| Name | Description
| ---- | -----------
| `default_repository_root` | This property can take a URI that is used as a common root for all of the repositories used by the buildpack. The value is substituted for the `{default.repository.root}` variable in `repository_root` declarations.
+## Proxies
+Access to repositories may be affected by the existence of network proxies. In order to configure the buildpack to use a proxy, set the `http_proxy`, `HTTP_PROXY`, `https_proxy`, or `HTTPS_PROXY` environment variables with the property proxy URI. Proxy authentication crendentials can be embedded in the URI if needed.
+
+```bash
+cf set-env http_proxy http://username:password@host:port
+```
+
## Version Syntax and Ordering
Versions are composed of major, minor, micro, and optional qualifier parts (`..[_]`). The major, minor, and micro parts must be numeric. The qualifier part is composed of letters, digits, and hyphens. The lexical ordering of the qualifier is:
@@ -86,5 +95,5 @@ In addition to declaring a specific versions to use, you can also specify a boun
[`config/repository.yml`]: ../config/repository.yml
[`JavaBuildpack::Repository::ConfiguredItem`]: ../lib/java_buildpack/repository/configured_item.rb
[Configuration and Extension]: ../README.md#configuration-and-extension
-[example]: http://download.pivotal.io.s3.amazonaws.com/openjdk/lucid/x86_64/index.yml
+[example]: https://java-buildpack.cloudfoundry.org/openjdk/jammy/x86_64/index.yml
diff --git a/docs/extending-utilities.md b/docs/extending-utilities.md
deleted file mode 100644
index 2b8f0b8fc8..0000000000
--- a/docs/extending-utilities.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# Other Utiltities
-The buildpack provides a number of other utilities that may help in implementing components.
-
-## [`JavaBuildpack::Util::ClassFileUtils`][]
-The `ClassFileUtils` class provides a method for getting all of the class files in an application.
-
-## [`JavaBuildpack::Util::ConfigurationUtils`][]
-The `ConfigurationUtils` class provides a method for getting the parsed contents of a configuration file from the buildpack configuration directory.
-
-## [`JavaBuildpack::Util::GroovyUtils`][]
-The `GroovyUtils` class provides a set of methods for finding groovy files and determing if they are of any special kind (e.g. they have a main method, they are a pogo, etc.).
-
-## [`JavaBuildpack::Util::JavaMainUtils`][]
-The `JavaMainUtils` class provides a a set of methods for determining the Java main class of an application if it exists.
-
-## [`JavaBuildpack::Util::Properties`][]
-The `Properties` class provides a Ruby class that can read in a Java properties file and acts as a `Hash` with that data.
-
-## [`JavaBuildpack::Util::Shell`][]
-The `shell` method encapsulates a standard shell invocation in the buildpack. It ensures that the output of the command is suppressed unless the command fails. When that happens, the content of `stdout` and `stderr` are printed. This method is mixed into the `BaseComponent` class and all of its subclasses.
-
-
-[`JavaBuildpack::Util::ClassFileUtils`]: ../lib/java_buildpack/util/class_file_utils.rb
-[`JavaBuildpack::Util::ConfigurationUtils`]: ../lib/java_buildpack/util/configuration_utils.rb
-[`JavaBuildpack::Util::GroovyUtils`]: ../lib/java_buildpack/util/groovy_utils.rb
-[`JavaBuildpack::Util::JavaMainUtils`]: ../lib/java_buildpack/util/java_main_utils.rb
-[`JavaBuildpack::Util::Properties`]: ../lib/java_buildpack/util/properties.rb
-[`JavaBuildpack::Util::Shell`]: ../lib/java_buildpack/util/shell.rb
diff --git a/docs/extending-versioned_dependency_component.md b/docs/extending-versioned_dependency_component.md
deleted file mode 100644
index f3bbddb24f..0000000000
--- a/docs/extending-versioned_dependency_component.md
+++ /dev/null
@@ -1,85 +0,0 @@
-# `JavaBuildpack::Component::VersionedDependencyComponent`
-This base class is recommended for use by any component that uses the buildpack [repository support][] to download a dependency. It ensures that each component has a `@version` and `@uri` that were resolved from the repository specified in the component's configuration. It also implements the `detect` method with a standard implementation.
-
-## Required Method Implementations
-
-```ruby
-# Modifies the application's file system. The component is expected to transform the application's file system in
-# whatever way is necessary (e.g. downloading files or creating symbolic links) to support the function of the
-# component. Status output written to +STDOUT+ is expected as part of this invocation.
-#
-# @return [void]
-def compile
-
-# Modifies the application's runtime configuration. The component is expected to transform members of the +context+
-# (e.g. +@java_home+, +@java_opts+, etc.) in whatever way is necessary to support the function of the component.
-#
-# Container components are also expected to create the command required to run the application. These components
-# are expected to read the +context+ values and take them into account when creating the command.
-#
-# @return [void, String] components other than containers are not expected to return any value. Container
-# components are expected to return the command required to run the application.
-def release
-
-# Whether or not this component supports this application
-#
-# @return [Boolean] whether or not this component supports this application
-def supports?
-```
-
-## Exposed Instance Variables
-
-| Name | Type
-| ---- | ----
-| `@application` | [`JavaBuildpack::Component::Application`][]
-| `@component_name` | `String`
-| `@configuration` | `Hash`
-| `@droplet` | [`JavaBuildpack::Component::Droplet`][]
-| `@uri` | `String`
-| `@version` | `JavaBuildpack::Util::TokenizedVersion`
-
-
-## Helper Methods
-
-```ruby
-# Downloads an item with the given name and version from the given URI, then yields the resultant file to the given
-# block.
-#
-# @param [JavaBuildpack::Util::TokenizedVersion] version
-# @param [String] uri
-# @param [String] name an optional name for the download. Defaults to +@component_name+.
-# @return [void]
-def download(version, uri, name = @component_name, &block)
-
-# Downloads a given JAR file and stores it.
-#
-# @param [String] jar_name the name to save the jar as
-# @param [Pathname] target_directory the directory to store the JAR file in. Defaults to the component's sandbox.
-# @param [String] name an optional name for the download. Defaults to +@component_name+.
-def download_jar(jar_name = jar_name, target_directory = @droplet.sandbox, name = @component_name)
-
-# Downloads a given TAR file and expands it.
-#
-# @param [Pathname] target_directory the directory to expand the TAR file to. Defaults to the component's sandbox.
-# @param [String] name an optional name for the download and expansion. Defaults to +@component_name+.
-def download_tar(target_directory = @droplet.sandbox, name = @component_name)
-
-# Downloads a given ZIP file and expands it.
-#
-# @param [Boolean] strip_top_level whether to strip the top-level directory when expanding. Defaults to +true+.
-# @param [Pathname] target_directory the directory to expand the ZIP file to. Defaults to the component's sandbox.
-# @param [String] name an optional name for the download. Defaults to +@component_name+.
-def download_zip(strip_top_level = true, target_directory = @droplet.sandbox, name = @component_name)
-
-# A generated JAR name for the component. Meets the format +-.jar+
-def jar_name
-
-# Wrap the execution of a block with timing information
-#
-# @param [String] caption the caption to print when timing starts
-def with_timing(caption)
-```
-
-[`JavaBuildpack::Component::Application`]: extending-application.md
-[`JavaBuildpack::Component::Droplet`]: extending-droplet.md
-[repository support]: extending-repositories.md
diff --git a/docs/extending.md b/docs/extending.md
deleted file mode 100644
index 54131897f3..0000000000
--- a/docs/extending.md
+++ /dev/null
@@ -1,86 +0,0 @@
-# Extending
-For general information on extending the buildpack, refer to [Configuration and Extension](../README.md#configuration-and-extension).
-
-To add a component, its class name must be added added to [`config/components.yml`][]. It is recommended, but not required, that the class' file be placed in a directory that matches its type.
-
-| Component Type | Location
-| -------------- | --------
-| Container | [`lib/java_buildpack/container`][]
-| Framework | [`lib/java_buildpack/framework`][]
-| JRE | [`lib/java_buildpack/jre`][]
-
-## Component Class Contract
-Each component class must satisfy a contract defined by the following methods:
-
-```ruby
-# If the component should be used when staging an application
-#
-# @return [Array, String, nil] If the component should be used when staging the application, a +String+ or
-# an +Array+ that uniquely identifies the component (e.g.
-# +open_jdk-1.7.0_40+). Otherwise, +nil+.
-def detect
-
-# Modifies the application's file system. The component is expected to transform the application's file system in
-# whatever way is necessary (e.g. downloading files or creating symbolic links) to support the function of the
-# component. Status output written to +STDOUT+ is expected as part of this invocation.
-#
-# @return [void]
-def compile
-
-# Modifies the application's runtime configuration. The component is expected to transform members of the +droplet+
-# (e.g. +java_home+, +java_opts+, etc.) in whatever way is necessary to support the function of the component.
-#
-# Container components are also expected to create the command required to run the application. These components
-# are expected to read the +droplet+ values and take them into account when creating the command.
-#
-# @return [void, String] components other than containers are not expected to return any value. Container
-# compoonents are expected to return the command required to run the application.
-def release
-```
-
-## Component Context
-Each component class must have an `initialize` method that takes a `Hash` containing helper types for the application. These helper types are the way that components to communicate with one another. The context contains the following entries:
-
-| Name | Type | Description
-| ---- | ---- | -----------
-| `application` | [`JavaBuildpack::Component::Application`][] | A read-only abstraction around the application
-| `configuration` | `Hash` | The component configuration provided by the user via `config/.yml`
-| `droplet` | [`JavaBuildpack::Component::Droplet`][] | A read-write abstraction around the droplet
-
-
-## Base Classes
-The buildpack provides a collection of base classes that may help you implement a component.
-
-### [`JavaBuildpack::Component::BaseComponent`][]
-This base class is recommended for use by all components. It ensures that each component has a name, and that the contents of the context are exposed as instance variables (e.g. `context[:application]` is available as `@application`). In addition it provides two helper methods for downloading files as part of the component's operation.
-
-### [`JavaBuildpack::Component::ModularComponent`][]
-This base class is recommended for use by any component that is sufficiently complex to need modularization. It enables a component to be composed of multiple "sub-components" and coordinates the component lifecycle across all of them.
-
-### [`JavaBuildpack::Component::VersionedDependencyComponent`][]
-This base class is recommended for use by any component that uses the buildpack [repository support][] to download a dependency. It ensures that each component has a `@version` and `@uri` that were resolved from the repository specified in the component's configuration. It also implements the `detect` method with a standard implementation.
-
-## Examples
-The following example components are relatively simple and good for copying as the basis for a new component.
-
-### Java Main Class Container
-The [Java Main Class Container](container-java_main.md) ([`lib/java_buildpack/container/java_main.rb`](../lib/java_buildpack/container/main.rb)) extends the [`JavaBuildpack::Component::BaseComponent`](../lib/java_buildpack/component/base_component.rb) base class described above.
-
-### Tomcat Container
-The [Tomcat Container](container-tomcat.md) ([`lib/java_buildpack/container/tomcat.rb`](../lib/java_buildpack/container/tomcat.rb)) extends the [`JavaBuildpack::Component::ModularComponent`](../lib/java_buildpack/component/modular_component.rb) base class described above.
-
-### Spring Boot CLI Container
-The [Spring Boot CLI Container](container-spring_boot_cli.md) ([`lib/java_buildpack/container/spring_boot_cli.rb`](../lib/java_buildpack/container/spring_boot_cli.rb)) extends the [`JavaBuildpack::Component::VersionedDependencyComponent`](../lib/java_buildpack/component/versioned_dependency_component.rb) base class described above.
-
-[`config/components.yml`]: ../config/components.yml
-[`JavaBuildpack::Component::Application`]: extending-application.md
-[`JavaBuildpack::Component::BaseComponent`]: extending-base_component.md
-[`JavaBuildpack::Component::Droplet`]: extending-droplet.md
-[`JavaBuildpack::Component::ModularComponent`]: extending-modular_component.md
-[`JavaBuildpack::Component::VersionedDependencyComponent`]: extending-versioned_dependency_component.md
-[`lib/java_buildpack/container`]: ../lib/java_buildpack/container
-[`lib/java_buildpack/framework`]: ../lib/java_buildpack/framework
-[`lib/java_buildpack/jre`]: ../lib/java_buildpack/jre
-[repository support]: extending-repositories.md
-
-
diff --git a/docs/framework-app_dynamics_agent.md b/docs/framework-app_dynamics_agent.md
index f02d9f80e8..37dba6aeee 100644
--- a/docs/framework-app_dynamics_agent.md
+++ b/docs/framework-app_dynamics_agent.md
@@ -1,9 +1,9 @@
# AppDynamics Agent Framework
-The AppDynamics Agent Framework causes an application to be automatically configured to work with a bound [AppDynamics Service][].
+The AppDynamics Agent Framework causes an application to be automatically configured to work with a bound [AppDynamics Service][]. **Note:** This framework is disabled by default.
- | Detection Criterion | Existence of a single bound AppDynamics service. The existence of an AppDynamics service defined by the VCAP_SERVICES payload containing a service name, label or tag with app-dynamics as a substring.
+ | Detection Criterion | Existence of a single bound AppDynamics service. The existence of an AppDynamics service defined by the VCAP_SERVICES payload containing a service name, label or tag with app-dynamics or appdynamics as a substring.
|
@@ -13,30 +13,97 @@ The AppDynamics Agent Framework causes an application to be automatically config
Tags are printed to standard output by the buildpack detect script
## User-Provided Service
-When binding AppDynamics using a user-provided service, it must have name or tag with `app-dynamics` in it. The credential payload can contain the following entries:
+When binding AppDynamics using a user-provided service, it must have name or tag with `app-dynamics` or `appdynamics` in it. The credential payload can contain the following entries.
| Name | Description
| ---- | -----------
-| `account-access-key` | (Optional) The account access key to use when authenticating with the controller
-| `account-name` | (Optional) The account name to use when authenticating with the controller
+| `account-access-key` | The account access key to use when authenticating with the controller
+| `account-name` | The account name to use when authenticating with the controller
| `host-name` | The controller host name
-| `port` | (Optional) The controller port
-| `ssl-enabled` | (Optional) Whether or not to use an SSL connection to the controller
+| `port` | The controller port
+| `ssl-enabled` | Whether or not to use an SSL connection to the controller
+| `application-name` | (Optional) the application's name
+| `node-name` | (Optional) the application's node name
+| `tier-name` | (Optional) the application's tier name
+
+To provide more complex values such as the `tier-name`, using the interactive mode when creating a user-provided service will manage the character escaping automatically. For example, the default `tier-name` could be set with a value of `Tier-$(expr "${VCAP_APPLICATION}" : '.*instance_index[": ]*\([[:digit:]]*\).*')` to calculate a value from the Cloud Foundry instance index.
+
+**Note:** Some credentials were previously marked as "(Optional)" as requirements have changed across versions of the AppDynamics agent. Please see the [AppDynamics Java Agent Configuration Properties][] for the version of the agent used by your application for more details.
## Configuration
-For general information on configuring the buildpack, refer to [Configuration and Extension][].
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
-The framework can be configured by modifying the [`config/app_dynamics_agent.yml`][] file. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+The framework can be configured by modifying the [`config/app_dynamics_agent.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
| Name | Description
| ---- | -----------
+| `default_application_name` | This is omitted by default but can be added to specify the application name in the AppDynamics dashboard. This can be overridden by an `application-name` entry in the credentials payload. If neither are supplied the default is the `application_name` as specified by Cloud Foundry.
+| `default_node_name` | The default node name for this application in the AppDynamics dashboard. The default value is an expression that will be evaluated based on the `instance_index` of the application. This can be overridden by a `node-name` entry in the credentials payload.
+| `default_tier_name` | This is omitted by default but can be added to specify the tier name for this application in the AppDynamics dashboard. This can be overridden by a `tier-name` entry in the credentials payload. If neither are supplied the default is the `application_name` as specified by Cloud Foundry.
| `repository_root` | The URL of the AppDynamics repository index ([details][repositories]).
| `version` | The version of AppDynamics to use. Candidate versions can be found in [this listing][].
+### Additional Resources
+The framework can be configured by providing custom configuration files.
+
+#### Default Configuration
+The buildpack includes a default `app-agent-config.xml` configuration file that is embedded at compile time. This default configuration provides sensible defaults for Cloud Foundry deployments, including sensitive data filtering for passwords and keys.
+
+The default configuration file is located in `src/java/resources/files/app_dynamics_agent/defaults/conf/app-agent-config.xml`.
+
+##### Customizing Default Configuration via Fork
+To customize the default AppDynamics configuration across all applications using your buildpack:
+
+1. Fork the java-buildpack repository
+2. Modify the configuration file in `src/java/resources/files/app_dynamics_agent/defaults/conf/`
+3. Build and package your custom buildpack
+4. Upload the custom buildpack to your Cloud Foundry foundation
+
+This approach is useful for operators who want to enforce organization-wide AppDynamics settings.
+
+Configuration files are applied in this order:
+
+1. Default AppDynamics configuration (embedded in buildpack)
+2. External Configuration (if configured via `APPD_CONF_HTTP_URL`)
+3. Local Configuration (if configured via `APPD_CONF_DIR`)
+
+#### External Configuration
+Set `APPD_CONF_HTTP_URL` to an HTTP or HTTPS URL which points to the directory where your configuration files exist. You may also include a user and password in the URL, like `https://user:pass@example.com`.
+
+The Java buildpack will take the URL to the directory provided and attempt to download the following files from that directory:
+
+- `logging/log4j2.xml`
+- `logging/log4j.xml`
+- `app-agent-config.xml`
+- `controller-info.xml`
+- `service-endpoint.xml`
+- `transactions.xml`
+- `custom-interceptors.xml`
+- `custom-activity-correlation.xml`
+
+Any file successfully downloaded will be copied to the configuration directory. The buildpack does not fail if files are missing.
+
+#### Local Configuration
+Set `APPD_CONF_DIR` to a relative path which points to the directory in your application files where your custom configuration exists.
+
+The Java buildpack will take the `app_root` + `APPD_CONF_DIR` directory and attempt to copy the followinig files from that directory:
+
+- `logging/log4j2.xml`
+- `logging/log4j.xml`
+- `app-agent-config.xml`
+- `controller-info.xml`
+- `service-endpoint.xml`
+- `transactions.xml`
+- `custom-interceptors.xml`
+- `custom-activity-correlation.xml`
+
+Any files that exist will be copied to the configuration directory. The buildpack does not fail if files are missing.
+
[`config/app_dynamics_agent.yml`]: ../config/app_dynamics_agent.yml
+[AppDynamics Java Agent Configuration Properties]: https://docs.appdynamics.com/display/PRO42/Java+Agent+Configuration+Properties
[AppDynamics Service]: http://www.appdynamics.com
[Configuration and Extension]: ../README.md#configuration-and-extension
[repositories]: extending-repositories.md
-[this listing]: http://download.pivotal.io.s3.amazonaws.com/app-dynamics/index.yml
+[this listing]: https://packages.appdynamics.com/java/index.yml
[version syntax]: extending-repositories.md#version-syntax-and-ordering
diff --git a/docs/framework-aspectj_weaver_agent.md b/docs/framework-aspectj_weaver_agent.md
new file mode 100644
index 0000000000..926315defe
--- /dev/null
+++ b/docs/framework-aspectj_weaver_agent.md
@@ -0,0 +1,26 @@
+# AspectJ Weaver Agent Framework
+The AspectJ Weaver Agent Framework configures the AspectJ Runtime Weaving Agent at runtime.
+
+
+
+ | Detection Criterion |
+ aspectjweaver-*.jar existing and BOOT-INF/classes/META-INF/aop.xml, BOOT-INF/classes/org/aspectj/aop.xml, META-INF/aop.xml, or org/aspectj/aop.xml existing. |
+
+
+ | Tags |
+ aspectj-weaver-agent=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by creating or modifying the [`config/aspectj_weaver_agent.yml`][] file in the buildpack fork.
+
+| Name | Description
+| ---- | -----------
+| `enabled` | Whether to enable the AspectJ Runtime Weaving agent.
+
+[`config/aspectj_weaver_agent.yml`]: ../config/aspect_weaver_agent.yml
+[Configuration and Extension]: ../README.md#configuration-and-extension
diff --git a/docs/framework-azure_application_insights_agent.md b/docs/framework-azure_application_insights_agent.md
new file mode 100644
index 0000000000..5225df33b5
--- /dev/null
+++ b/docs/framework-azure_application_insights_agent.md
@@ -0,0 +1,67 @@
+# Azure Application Insights Agent Framework
+The Azure Application Insights Agent Framework causes an application to be automatically configured to work with a bound [Azure Application Insights Service][]. **Note:** This framework is disabled by default.
+
+
+
+ | Detection Criterion | Existence of a single bound Azure Application Insights service.
+
+ - Existence of a Azure Application Insights service is defined as the
VCAP_SERVICES payload containing a service who's name, label or tag has azure-application-insights as a substring with at least `connection_string` or `instrumentation_key` set as credentials.
+
+ |
+
+
+ | Tags |
+ azure-application-insights=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## User-Provided Service
+Users must provide their own Azure Application Insights service. A user-provided Azure Application Insights service must have a name or tag with `azure-application-insights` in it so that the Azure Application Insights Agent Framework Framework will automatically configure the application to work with the service.
+
+The credential payload of the service has to contain one of the following entries:
+
+| Name | Description | Status |
+| ---- | ----------- | ------ |
+| `connection_string` | **REQUIRED** for agent version 3.x+. You can find your connection string in your Application Insights resource. | ✅ **Recommended** |
+| `instrumentation_key` | Required for agent version 2.x. **⚠️ DEPRECATED in version 3.x** - switch to `connection_string` instead. | ⚠️ **Deprecated** |
+
+### ⚠️ Deprecation Warning: instrumentation_key
+
+**The `instrumentation_key` credential is deprecated** in Azure Application Insights agent version 3.x and later.
+
+**Action Required**:
+- **New deployments**: Use `connection_string` instead of `instrumentation_key`
+- **Existing deployments**: Migrate to `connection_string` before upgrading to agent v3.x
+
+**How to migrate**:
+1. Get your connection string from your Application Insights resource in Azure Portal
+2. Update your user-provided service credentials:
+ ```bash
+ cf update-user-provided-service my-app-insights -p '{"connection_string": "InstrumentationKey=xxx;IngestionEndpoint=https://..."}'
+ ```
+3. Restage your application:
+ ```bash
+ cf restage my-app
+ ```
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+### Default Configuration
+The buildpack includes a default `AI-Agent.xml` configuration file that is embedded at compile time. This provides sensible defaults for Cloud Foundry deployments.
+
+The default configuration file is located in `src/java/resources/files/azure_application_insights_agent/AI-Agent.xml`.
+
+#### Customizing Default Configuration via Fork
+To customize the default Azure Application Insights configuration across all applications using your buildpack:
+
+1. Fork the java-buildpack repository
+2. Modify the configuration file in `src/java/resources/files/azure_application_insights_agent/`
+3. Build and package your custom buildpack
+4. Upload the custom buildpack to your Cloud Foundry foundation
+
+This approach is useful for operators who want to enforce organization-wide Azure Application Insights settings.
+
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[Azure Application Insights Service]: https://learn.microsoft.com/en-us/azure/azure-monitor/app/java-in-process-agent
diff --git a/docs/framework-cf_metrics_exporter.md b/docs/framework-cf_metrics_exporter.md
new file mode 100644
index 0000000000..3d2d44b461
--- /dev/null
+++ b/docs/framework-cf_metrics_exporter.md
@@ -0,0 +1,40 @@
+# cf-metrics-exporter (Agent Mode)
+
+This framework integrates the [cf-metrics-exporter](https://github.com/rabobank/cf-metrics-exporter) as a Java agent in the Java buildpack.
+
+## Enabling the Exporter
+
+Set the following environment variable in the cloud foundry env to enable the agent (via manifest.yml or `cf set-env`):
+
+```
+CF_METRICS_EXPORTER_ENABLED=true
+```
+
+## Configuration
+
+- **CF_METRICS_EXPORTER_ENABLED**: Set to `true` to enable the agent (default: disabled).
+- **CF_METRICS_EXPORTER_PROPS**: (Optional) Properties string to pass to the agent, e.g. `enableLogEmitter,rpsType=tomcat-bean`.
+
+## How it Works
+
+- The agent JAR is downloaded during the buildpack supply phase.
+- The agent is injected into the JVM at runtime using the `-javaagent` option.
+- If `CF_METRICS_EXPORTER_PROPS` is set, its value is appended to the `-javaagent` option.
+
+## Example
+
+```
+CF_METRICS_EXPORTER_ENABLED=true
+CF_METRICS_EXPORTER_PROPS="enableLogEmitter,rpsType=tomcat-bean"
+```
+
+## Version
+
+- Default version: 0.7.1
+- Default download URI: https://github.com/rabobank/cf-metrics-exporter/releases/download/0.7.1/cf-metrics-exporter-0.7.1.jar
+
+## Notes
+
+- The agent is injected with priority 43 in JAVA_OPTS (after other APM agents).
+
+
diff --git a/docs/framework-checkmarx_iast_agent.md b/docs/framework-checkmarx_iast_agent.md
new file mode 100644
index 0000000000..45a938def6
--- /dev/null
+++ b/docs/framework-checkmarx_iast_agent.md
@@ -0,0 +1,22 @@
+# Checkmarx IAST Agent Framework
+The Checkmarx IAST Agent Framework causes an application to be automatically configured to work with a bound [Checkmarx IAST Service][].
+
+
+
+ | Detection Criterion | Existence of a bound Checkmarx IAST service. The existence of an Checkmarx IAST service is defined by the VCAP_SERVICES payload containing a service named checkmarx-iast.
+ |
+
+
+
+## User-Provided Service
+When binding Checkmarx IAST using a user-provided service, it must have the name `checkmarx-iast` and the credential payload must include the following entry:
+
+| Name | Description
+| ---- | -----------
+| `server` | The IAST Manager URL
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+[Checkmarx IAST Service]: https://www.checkmarx.com/products/interactive-application-security-testing
+[Configuration and Extension]: ../README.md#configuration-and-extension
diff --git a/docs/framework-client_certificate_mapper.md b/docs/framework-client_certificate_mapper.md
new file mode 100644
index 0000000000..5d3852b5a6
--- /dev/null
+++ b/docs/framework-client_certificate_mapper.md
@@ -0,0 +1,37 @@
+# Client Certificate Mapper
+The Client Certificate Mapper Framework adds a Servlet Filter to applications that will that maps the `X-Forwarded-Client-Cert` to the `javax|jakarta.servlet.request.X509Certificate` Servlet attribute.
+
+The Client Certificate Mapper Framework will download a helper library, [java-buildpack-client-certificate-mapper][library repository], that will enrich Spring Boot (2 and 3), as well as JEE / JakartaEE applications classpath with a servlet filter.
+
+
+
+ | Detection Criterion |
+ Unconditional |
+
+
+ | Tags |
+ client-certificate-mapper=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by modifying the [`config/client_certificate_mapper.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+| Name | Description
+|-------------------| -----------
+| `repository_root` | The URL of the Container Customizer repository index ([details][repositories]).
+| `version` | The version of Container Customizer to use. Candidate versions can be found in [this listing][].
+
+## Servlet Filter
+The [Servlet Filter][] added by this framework maps the `X-Forwarded-Client-Cert` to the `javax.servlet.request.X509Certificate` Servlet attribute for each request. The `X-Forwarded-Client-Cert` header is contributed by the Cloud Foundry Router and contains the any TLS certificate presented by a client for mututal TLS authentication. This certificate can then be used by any standard Java security framework to establish authentication and authorization for a request.
+
+[`config/client_certificate_mapper.yml`]: ../config/client_certificate_mapper.yml
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[repositories]: extending-repositories.md
+[Servlet Filter]: https://github.com/cloudfoundry/java-buildpack-client-certificate-mapper
+[this listing]: http://download.pivotal.io.s3.amazonaws.com/container-security-provider/index.yml
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
+[library repository]: https://github.com:cloudfoundry/java-buildpack-client-certificate-mapper.git
diff --git a/docs/framework-container_customizer.md b/docs/framework-container_customizer.md
new file mode 100644
index 0000000000..97538ea05e
--- /dev/null
+++ b/docs/framework-container_customizer.md
@@ -0,0 +1,30 @@
+# Container Customizer Framework
+The Container Customizer Framework modifies the configuration of an embedded Tomcat container in a Spring Boot WAR file.
+
+
+
+ | Detection Criterion |
+ Application is a Spring Boot WAR file |
+
+
+ | Tags |
+ container-customizer=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by modifying the [`config/container_customizer.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+| Name | Description
+| ---- | -----------
+| `repository_root` | The URL of the Container Customizer repository index ([details][repositories]).
+| `version` | The version of Container Customizer to use. Candidate versions can be found in [this listing][].
+
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[`config/container_customizer.yml`]: ../config/container_customizer.yml
+[repositories]: extending-repositories.md
+[this listing]: http://download.pivotal.io.s3.amazonaws.com/container-customizer/index.yml
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
diff --git a/docs/framework-container_security_provider.md b/docs/framework-container_security_provider.md
new file mode 100644
index 0000000000..bb5f7c4223
--- /dev/null
+++ b/docs/framework-container_security_provider.md
@@ -0,0 +1,39 @@
+# Container Security Provider
+The Container Security Provider Framework adds a Security Provider to the JVM that automatically includes BOSH trusted certificates and Diego identity certificates and private keys.
+
+
+
+ | Detection Criterion |
+ Unconditional |
+
+
+ | Tags |
+ container-security-provider=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by modifying the [`config/container_security_provider.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+| Name | Description
+| ---- | -----------
+| `repository_root` | The URL of the Container Customizer repository index ([details][repositories]).
+| `version` | The version of Container Customizer to use. Candidate versions can be found in [this listing][].
+| `key_manager_enabled` | Whether the container `KeyManager` is enabled. Defaults to `true`.
+| `trust_manager_enabled` | Whether the container `TrustManager` is enabled. Defaults to `true`.
+
+## Security Provider
+The [security provider][] added by this framework contributes two types, a `TrustManagerFactory` and a `KeyManagerFactory`. The `TrustManagerFactory` adds an additional new `TrustManager` after the configured system `TrustManager` which reads the contents of `/etc/ssl/certs/ca-certificates.crt` which is where [BOSH trusted certificates][] are placed. The `KeyManagerFactory` adds an additional `KeyManager` after the configured system `KeyManager` which reads the contents of the files specified by `$CF_INSTANCE_CERT` and `$CF_INSTANCE_KEY` which are set by Diego to give each container a unique cryptographic identity. These `TrustManager`s and `KeyManager`s are used transparently by any networking library that reads standard system SSL configuration and can be used to enable system-wide trust and [mutual TLS authentication][].
+
+
+[`config/container_security_provider.yml`]: ../config/container_security_provider.yml
+[BOSH trusted certificates]: https://bosh.io/docs/trusted-certs.html
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[mutual TLS authentication]: https://en.wikipedia.org/wiki/Mutual_authentication
+[repositories]: extending-repositories.md
+[security provider]: https://github.com/cloudfoundry/java-buildpack-security-provider
+[this listing]: http://download.pivotal.io.s3.amazonaws.com/container-security-provider/index.yml
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
diff --git a/docs/framework-contrast_security_agent.md b/docs/framework-contrast_security_agent.md
new file mode 100644
index 0000000000..ab6e5d4ea0
--- /dev/null
+++ b/docs/framework-contrast_security_agent.md
@@ -0,0 +1,39 @@
+# Contrast Security Agent Framework
+The Contrast Security Agent Framework causes an application to be automatically configured to work with a bound [Contrast Security Service][].
+
+
+
+ | Detection Criterion | Existence of a single bound Contrast Security service. The existence of an Contrast Security service defined by the VCAP_SERVICES payload containing a service name, label or tag with contrast-security as a substring.
+ |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## User-Provided Service
+When binding ContrastSecurity using a user-provided service, it must have name or tag with `contrast-security` in it. The credential payload can contain the following entries:
+
+| Name | Description
+| ---- | -----------
+| `api_key` | Your user's api key
+| `service_key` | Your user's service key
+| `teamserver_url` | The base URL in which your user has access to and the URL to which the Agent will report. ex: https://app.contrastsecurity.com
+| `username` | The account name to use when downloading the agent
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by modifying the [`config/contrast_security_agent.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+| Name | Description
+| ---- | -----------
+| `repository_root` | The URL of the Contrast Security repository index ([details][repositories]).
+| `version` | The version of Contrast Security to use. Candidate versions can be found in [this listing][].
+
+[Contrast Security]: https://www.contrastsecurity.com
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[Contrast Security Service]: https://www.contrastsecurity.com
+[`config/contrast_security_agent.yml`]: ../config/contrast_security_agent.yml
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[repositories]: extending-repositories.md
+[this listing]: https://artifacts.contrastsecurity.com/agents/java/index.yml
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
diff --git a/docs/framework-datadog_javaagent.md b/docs/framework-datadog_javaagent.md
new file mode 100644
index 0000000000..b5efa52f37
--- /dev/null
+++ b/docs/framework-datadog_javaagent.md
@@ -0,0 +1,46 @@
+# Datadog APM Javaagent Framework
+The [Datadog APM]() Javaagent Framework installs an agent that allows your application to be dynamically instrumented [by][datadog-javaagent] `dd-java-agent.jar`.
+
+For this functionality to work, you **must** also use this feature in combination with the [Datadog Cloudfoundry Buildpack](). The Datadog Cloudfoundry Buildpack **must** run first, so that it can supply the components to which the Datadog APM agent will talk. Please make sure you follow the instructions on the README for the Datadog Cloudfoundry Buildpack to enable and configure it.
+
+The framework will configure the Datadog agent for correct use in most situations, however you may adjust its behavior by setting additional environment variables. For a complete list of Datadog Agent configuration options, please see the [Datadog Documentation](https://docs.datadoghq.com/tracing/setup_overview/setup/java/?tab=containers#configuration).
+
+
+
+ | Detection Criterion | All must be true:
+
+ - The Datadog Buildpack must be included
+ DD_API_KEY defined and contain your API key
+
+ Optionally, you may set DD_APM_ENABLED to false to force the framework to not contribute the agent.
+ |
+
+
+ | Tags |
+ datadog-javaagent=<version> |
+
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+The javaagent can be configured directly via environment variables or system properties as defined in the [Configuration of Datadog Javaagent][] documentation.
+
+
+| Name | Description
+| ---- | -----------
+| `repository_root` | The URL of the Datadog Javaagent repository index ([details][repositories]).
+| `version` | The `dd-java-agent` version to use. Candidate versions can be found in [this listing][].
+
+
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[Datadog APM]: https://www.datadoghq.com/product/apm/
+[Datadog Cloudfoundry Builpack]: https://github.com/DataDog/datadog-cloudfoundry-buildpack
+[datadog-javaagent]: https://github.com/datadog/dd-trace-java
+[Configuration of Datadog Javaagent]: https://docs.datadoghq.com/tracing/setup_overview/setup/java/#configuration
+[this listing]: https://raw.githubusercontent.com/datadog/dd-trace-java/cloudfoundry/index.yml
+[repositories]: extending-repositories.md
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
diff --git a/docs/framework-debug-eclipse.png b/docs/framework-debug-eclipse.png
new file mode 100644
index 0000000000..e01c28d329
Binary files /dev/null and b/docs/framework-debug-eclipse.png differ
diff --git a/docs/framework-debug.md b/docs/framework-debug.md
new file mode 100644
index 0000000000..303ce3fe2b
--- /dev/null
+++ b/docs/framework-debug.md
@@ -0,0 +1,41 @@
+# Debug Framework
+The Debug Framework contributes Java debug configuration to the application at runtime. **Note:** This framework is only useful in Diego-based containers with SSH access enabled.
+
+
+
+ | Detection Criterion |
+ enabled set in the config/debug.yml file |
+
+
+ | Tags |
+ debug=<port> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by creating or modifying the [`config/debug.yml`][] file in the buildpack fork.
+
+| Name | Description
+| ---- | -----------
+| `enabled` | Whether to enable Java debugging
+| `port` | The port that the debug agent will listen on. Defaults to `8000`.
+| `suspend` | Whether to suspend execution until a debugger has attached. Note, you cannot ssh to a container until the container has decided the application is running. Therefore when enabling this setting you must also push the application using the parameter `-u process` which disables container health checking.
+
+## Creating SSH Tunnel
+After starting an application with debugging enabled, an SSH tunnel must be created to the container. To create that SSH container, execute the following command:
+
+```bash
+$ cf ssh -N -T -L :localhost:
+```
+
+The `REMOTE_PORT` should match the `port` configuration for the application (`8000` by default). The `LOCAL_PORT` can be any open port on your computer, but typically matches the `REMOTE_PORT` where possible.
+
+Once the SSH tunnel has been created, your IDE should connect to `localhost:` for debugging.
+
+
+
+[`config/debug.yml`]: ../config/debug.yml
+[Configuration and Extension]: ../README.md#configuration-and-extension
diff --git a/docs/framework-dynatrace_one_agent.md b/docs/framework-dynatrace_one_agent.md
new file mode 100644
index 0000000000..938e39ef75
--- /dev/null
+++ b/docs/framework-dynatrace_one_agent.md
@@ -0,0 +1,65 @@
+# Dynatrace SaaS/Managed OneAgent Framework
+[Dynatrace SaaS/Managed](http://www.dynatrace.com/cloud-foundry/) is your full stack monitoring solution - powered by artificial intelligence. Dynatrace SaaS/Managed allows you insights into all application requests from the users click in the browser down to the database statement and code-level.
+
+The Java buildpack uses the [libbuildpack-dynatrace](https://github.com/Dynatrace/libbuildpack-dynatrace) library to automatically configure applications to work with a bound [Dynatrace SaaS/Managed Service][] instance (Free trials available).
+
+
+
+ | Detection Criterion | Existence of a single bound Dynatrace SaaS/Managed service.
+
+ - Existence of a Dynatrace SaaS/Managed service is defined as the
VCAP_SERVICES payload containing a service who's name, label or tag has dynatrace as a substring with at least `environmentid` and `apitoken` set as credentials.
+
+ |
+
+
+ | Tags |
+ dynatrace-one-agent=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## Implementation
+This buildpack integrates with Dynatrace using the [libbuildpack-dynatrace](https://github.com/Dynatrace/libbuildpack-dynatrace) hook library (v1.8.0). This is the same integration library used by all modern Cloud Foundry buildpacks (Go, Node.js, Python, PHP, etc.), ensuring consistent behavior across the platform.
+
+The integration:
+- Downloads and installs the Dynatrace OneAgent using the official PaaS installer
+- Configures `LD_PRELOAD` to inject the agent into the Java process
+- Fetches and merges the latest agent configuration from the Dynatrace API
+- Supports FIPS mode, network zones, and additional technologies
+- Provides retry logic and error handling for robust deployments
+
+## User-Provided Service
+Users must provide their own Dynatrace SaaS/Managed service. A user-provided Dynatrace SaaS/Managed service must have a name or tag with `dynatrace` in it so that the Dynatrace Saas/Managed OneAgent Framework will automatically configure the application to work with the service.
+
+The credential payload of the service may contain the following entries:
+
+| Name | Description
+| ---- | -----------
+| `apitoken` | The token for integrating your Dynatrace environment with Cloud Foundry. You can find it in the deploy Dynatrace section within your environment.
+| `apiurl` | (Optional) The base URL of the Dynatrace API. If you are using Dynatrace Managed you will need to set this property to `https:///e//api`. If you are using Dynatrace SaaS you don't need to set this property.
+| `environmentid` | Your Dynatrace environment ID is the unique identifier of your Dynatrace environment. You can find it in the deploy Dynatrace section within your environment.
+| `networkzone` | (Optional) Network zones are Dynatrace entities that represent your network structure. They help you to route the traffic efficiently, avoiding unnecessary traffic across data centers and network regions. Enter the network zone you wish to pass to the server during the OneAgent Download.
+| `skiperrors` | (Optional) The errors during agent download are skipped and the injection is disabled. Use this option at your own risk. Possible values are 'true' and 'false'. This option is disabled by default!
+| `enablefips`| (Optional) Enables the use of [FIPS 140 cryptographic algorithms](https://docs.dynatrace.com/docs/shortlink/oneagentctl#fips-140). Possible values are 'true' and 'false'. This option is disabled by default!
+| `addtechnologies` | (Optional) Adds additional OneAgent code-modules via a comma-separated list. See [supported values](https://docs.dynatrace.com/docs/dynatrace-api/environment-api/deployment/oneagent/download-oneagent-version#parameters) in the "included" row|
+| `customoneagenturl` | (Optional) Custom download URL for OneAgent. If set, `apiurl`, `environmentid`, and `apitoken` are not required.|
+
+Example:
+```bash
+cf create-user-provided-service dynatrace -p '{"environmentid":"abc12345","apitoken":"dt0c01.ABC...XYZ"}'
+cf bind-service my-app dynatrace
+cf restage my-app
+```
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+## Support
+For questions about the buildpack integration, please open an issue on the [java-buildpack GitHub repository](https://github.com/cloudfoundry/java-buildpack).
+
+For questions about Dynatrace itself, visit [Dynatrace support](https://support.dynatrace.com/).
+
+For technical details about the integration library, see [libbuildpack-dynatrace](https://github.com/Dynatrace/libbuildpack-dynatrace).
+
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[Dynatrace SaaS/Managed Service]: http://www.dynatrace.com/cloud-foundry/
diff --git a/docs/framework-elastic_apm_agent.md b/docs/framework-elastic_apm_agent.md
new file mode 100644
index 0000000000..55f09c5d15
--- /dev/null
+++ b/docs/framework-elastic_apm_agent.md
@@ -0,0 +1,67 @@
+# Elastic APM Agent Framework
+
+The Elastic APM Agent Framework causes an application to be automatically configured to work with [Elastic APM][].
+
+
+
+ | Detection Criterion |
+ Existence of a single bound Elastic APM service. The existence of an Elastic APM service defined by the VCAP_SERVICES payload containing a service name, label or tag with elastic-apm as a substring.
+ |
+
+ | Tags |
+ elastic-apm-agent=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## User-Provided Service
+When binding Elastic APM using a user-provided service, it must have name or tag with `elasticapm` or `elastic-apm` in it. The credential payload can contain the following entries.
+
+| Name | Description
+| ---- | -----------
+| `server_urls` | The URLs for the Elastic APM Server. They must be fully qualified, including protocol (http or https) and port.
+| `secret_token` (Optional)| This string is used to ensure that only your agents can send data to your APM server. Both the agents and the APM server have to be configured with the same secret token. Use if APM Server requires a token.
+| `***` (Optional) | Any additional entries will be applied as a system property appended to `-Delastic.apm.` to allow full configuration of the agent. See [Configuration of Elastic Agent][]. Values are shell-escaped by default, but do have limited support, use with caution, for incorporating subshells (i.e. `$(some-cmd)`) and accessing environment variables (i.e. `${SOME_VAR}`).
+
+
+### Creating an Elastic APM USer Provided Service
+Users must provide their own Elastic APM service. A user-provided Elastic APM service must have a name or tag with `elastic-apm` in it so that the Elastic APM Agent Framework will automatically configure the application to work with the service.
+
+Example of a minimal configuration:
+
+```
+cf cups my-elastic-apm-service -p '{"server_urls":"https://my-apm-server:8200","secret_token":"my-secret-token"}'
+```
+
+Example of a configuration with additional configuration parameters:
+
+```
+cf cups my-elastic-apm-service -p '{"server_urls":"https://my-apm-server:8200","secret_token":"","server_timeout":"10s","environment":"production"}'
+```
+
+Bind your application to the service using:
+
+`cf bind-service my-app-name my-elastic-apm-service`
+
+or use the `services` block in the application manifest file.
+
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by modifying the [`config/elastic_apm_agent.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+| Name | Description
+| ---- | -----------
+| `service_name` | This can be overridden by a `service_name` entry in the credentials payload. If neither are supplied the default is the application_name as specified by Cloud Foundry.
+| `repository_root` | The URL of the Elastic APM repository index ([details][repositories]).
+| `version` | The version of Elastic APM to use. Candidate versions can be found in [this listing][].
+
+
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[`config/elastic_apm_agent.yml`]: ../config/elastic_apm_agent.yml
+[Elastic APM]: https://www.elastic.co/guide/en/apm/agent/java/current/index.html
+[repositories]: extending-repositories.md
+[this listing]: https://raw.githubusercontent.com/elastic/apm-agent-java/master/cloudfoundry/index.yml
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
+[Configuration of Elastic Agent]: https://www.elastic.co/guide/en/apm/agent/java/current/configuration.html
diff --git a/docs/framework-google_stackdriver_profiler.md b/docs/framework-google_stackdriver_profiler.md
new file mode 100644
index 0000000000..7bc3fa645f
--- /dev/null
+++ b/docs/framework-google_stackdriver_profiler.md
@@ -0,0 +1,43 @@
+# Google Stackdriver Profiler Framework
+The Google Stackdriver Profiler Framework causes an application to be automatically configured to work with a bound [Google Stackdriver Profiler Service][].
+
+
+
+ | Detection Criterion | Existence of a single bound Google Stackdriver Profiler service.
+
+ - Existence of a Google Stackdriver Profiler service is defined as the
VCAP_SERVICES payload containing a service who's name, label or tag has google-stackdriver-profiler as a substring.
+
+ |
+
+
+ | Tags |
+ google-stackdriver-profiler=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## User-Provided Service (Optional)
+Users may optionally provide their own Google Stackdriver Profiler service. A user-provided Google Stackdriver Profiler service must have a name or tag with `google-stackdriver-profiler` in it so that the Google Stackdriver Profiler Agent Framework will automatically configure the application to work with the service.
+
+The credential payload of the service must contain the following entry:
+
+| Name | Description
+| ---- | -----------
+| `PrivateKeyData` | A Base64 encoded Service Account JSON payload
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by modifying the [`config/google_stackdriver_profiler.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+| Name | Description
+| ---- | -----------
+| `repository_root` | The URL of the Google Stackdriver Profiler repository index ([details][repositories]).
+| `version` | The version of Google Stackdriver Profiler to use. Candidate versions can be found in [this listing][].
+
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[`config/google_stackdriver_profiler.yml`]: ../config/google_stackdriver_profiler.yml
+[Google Stackdriver Profiler Service]: https://cloud.google.com/profiler/
+[repositories]: extending-repositories.md
+[this listing]: https://java-buildpack.cloudfoundry.org/google-stackdriver-profiler/jammy/x86_64/index.yml
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
diff --git a/docs/framework-introscope_agent.md b/docs/framework-introscope_agent.md
new file mode 100644
index 0000000000..c1234b882b
--- /dev/null
+++ b/docs/framework-introscope_agent.md
@@ -0,0 +1,56 @@
+# CA Introscope APM Framework
+The CA Introscope APM Framework causes an application to be automatically configured to work with a bound [Introscope service][].
+
+
+
+ | Detection Criterion | Existence of a single bound Introscope service.
+
+ - Existence of a Introscope service is defined as the
VCAP_SERVICES payload containing a service who's name, label or tag has introscope as a substring.
+
+ |
+
+
+ | Tags |
+ introscope-agent=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## User-Provided Service (Optional)
+Users may optionally provide their own Introscope service. A user-provided Introscope service must have a name or tag with `introscope` in it so that the Introscope Agent Framework will automatically configure the application to work with the service.
+
+The credential payload of the service may contain any valid CA APM Java agent property.
+
+The table below displays a subset of properties that are accepted by the buildpack.
+Please refer to CA APM docs for a full list of valid agent properties.
+
+
+| Name | Description
+| ---- | -----------
+|`agent_manager_credential`| (Optional) The credential that is used to connect to the Enterprise Manager server.
+|`agentManager_url_1` | The url of the Enterprise Manager server.
+|`agent_manager_url`| (Deprecated) The url of the Enterprise Manager server.
+|`credential`| (Deprecated) The credential that is used to connect to the Enterprise Manager server
+
+
+To provide more complex values such as the `agent_name`, using the interactive mode when creating a user-provided service will manage the character escaping automatically. For example, the default `agent_name` could be set with a value of `agent-$(expr "$VCAP_APPLICATION" : '.*application_name[": ]*\([[:word:]]*\).*')` to calculate a value from the Cloud Foundry application name.
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by modifying the [`config/introscope_agent.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+| Name | Description
+| ---- | -----------
+| `repository_root` | The URL of the Introscope Agent repository index ([details][repositories]).
+| `version` | The version of Introscope Agent to use.
+
+### Additional Resources
+
+**Note:** The `resources/introscope_agent` directory approach from the Ruby buildpack (2013-2025) is no longer supported. This was a **buildpack-level** feature where teams would fork the java-buildpack repository, add custom files to `resources/introscope_agent/`, and package their custom buildpack. The Go buildpack does not package the `resources/` directory.
+
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[`config/intoscope_agent.yml`]: ../config/intoscope_agent.yml
+[Introscope service]: http://www.ca.com/us/opscenter/ca-application-performance-management.aspx
+[repositories]: extending-repositories.md
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
diff --git a/docs/framework-jacoco_agent.md b/docs/framework-jacoco_agent.md
new file mode 100644
index 0000000000..f5d1a7a315
--- /dev/null
+++ b/docs/framework-jacoco_agent.md
@@ -0,0 +1,51 @@
+# JaCoco Agent Framework
+The JaCoCo Agent Framework causes an application to be automatically configured to work with a bound [JaCoCo Service][].
+
+
+
+ | Detection Criterion | Existence of a single bound JaCoCo service.
+
+ - Existence of a JaCoCo service is defined as the
VCAP_SERVICES payload containing a service who's name, label or tag has jacoco as a substring.
+
+ |
+
+
+ | Tags |
+ jacoco-agent=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## User-Provided Service (Optional)
+Users may optionally provide their own JaCoCo service. A user-provided JaCoCo service must have a name or tag with `jacoco` in it so that the JaCoCo Agent Framework will automatically configure the application to work with the service.
+
+The credential payload of the service may contain the following entries:
+
+| Name | Description
+| ---- | -----------
+| `address` | The host for the agent to connect to or listen on
+| `excludes` | (Optional) A list of class names that should be excluded from execution analysis. The list entries are separated by a colon (:) and may use wildcard characters (* and ?).
+| `includes` | (Optional) A list of class names that should be included in execution analysis. The list entries are separated by a colon (:) and may use wildcard characters (* and ?).
+| `port` | (Optional) The port for the agent to connect to or listen on
+| `output` | (Optional) The mode for the agent. Possible values are either tcpclient (default) or tcpserver.
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by modifying the [`config/jacoc_agent.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+| Name | Description
+| ---- | -----------
+| `repository_root` | The URL of the JaCoCo repository index ([details][repositories]).
+| `version` | The version of JaCoCo to use. Candidate versions can be found in [this listing][].
+
+### Additional Resources
+
+**Note:** The `resources/jacoco_agent` directory approach from the Ruby buildpack (2013-2025) is no longer supported. This was a **buildpack-level** feature where teams would fork the java-buildpack repository, add custom files to `resources/jacoco_agent/`, and package their custom buildpack. The Go buildpack does not package the `resources/` directory.
+
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[`config/jacoco_agent.yml`]: ../config/jacoco_agent.yml
+[JaCoCo Service]: http://www.jacoco.org/jacoco/
+[repositories]: extending-repositories.md
+[this listing]: https://java-buildpack.cloudfoundry.org/jacoco/index.yml
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
diff --git a/docs/framework-java-cfenv.md b/docs/framework-java-cfenv.md
new file mode 100644
index 0000000000..0a94b27e2f
--- /dev/null
+++ b/docs/framework-java-cfenv.md
@@ -0,0 +1,77 @@
+# Java CfEnv Framework
+The Java CfEnv Framework provides the `java-cfenv` library for Spring Boot 3.x and 4.x applications. This library sets various Spring Boot properties by parsing Cloud Foundry variables such as `VCAP_SERVICES`, allowing Spring Boot's autoconfiguration to kick in.
+
+This is the recommended replacement for Spring AutoReconfiguration library which is deprecated. See the `java-cfenv` repository for more details.
+
+The `cloud` Spring profile is activated at runtime by java-cfenv's `CloudProfileApplicationListener`, which ships in the `java-cfenv-all` module. To ensure the profile is active — or to activate it independently of java-cfenv — set it explicitly. Use `SPRING_PROFILES_INCLUDE=cloud` to add `cloud` alongside any other active profiles, or `SPRING_PROFILES_ACTIVE=cloud` to set it as the sole active profile (this replaces any others). The buildpack itself does not set any Spring profile.
+
+The buildpack selects the appropriate `java-cfenv` version based on the detected Spring Boot major version:
+
+| Spring Boot | java-cfenv |
+|-------------|------------|
+| 3.x | 3.x (latest) |
+| 4.x | 4.x (latest) |
+
+
+
+ | Detection Criterion |
+ Existence of a spring-boot-3.*.jar or spring-boot-4.*.jar in BOOT-INF/lib, WEB-INF/lib, or lib/; or a Spring-Boot-Version: 3.* / Spring-Boot-Version: 4.* entry in META-INF/MANIFEST.MF |
+ No existing java-cfenv library found in the application |
+
+
+ | Tags |
+ java-cf-env=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## How it works
+
+The framework is implemented in `src/java/frameworks/java_cf_env.go`:
+
+1. **Detect** — activates only when all of these hold: the framework is enabled (see [Configuration](#configuration)); a Spring Boot 3.x or 4.x marker is found (a `spring-boot-{3,4}.*.jar` under `BOOT-INF/lib`, `WEB-INF/lib`, or `lib/`, or a `Spring-Boot-Version: 3.*` / `4.*` entry in `META-INF/MANIFEST.MF`); and the application does not already bundle a `java-cfenv*.jar` (if it does, the buildpack backs off and uses the application's own copy).
+2. **Supply** — selects the java-cfenv version from the detected Spring Boot major (Spring Boot 3 → the manifest's `3.x` line, Spring Boot 4 → the `4.x` line) and installs the `java-cfenv-all` jar into the dependency directory.
+3. **Finalize** — appends the installed jar to `CLASSPATH` via a `.profile.d/java_cf_env.sh` script, so it is on the application's runtime classpath.
+4. **Runtime** — Spring Boot reads the jar's `META-INF/spring.factories`: the `EnvironmentPostProcessor`s map `VCAP_SERVICES` to Spring properties, and `CloudProfileApplicationListener` (in the `java-cfenv-all` module) activates the `cloud` profile when running in Cloud Foundry.
+
+## Configuration
+
+The framework can be disabled via the `JBP_CONFIG_JAVA_CF_ENV` environment variable:
+
+```bash
+cf set-env JBP_CONFIG_JAVA_CF_ENV '{enabled: false}'
+cf restage
+```
+
+The buildpack only re-reads this variable during staging, so a `cf restage` is required for the change to take effect.
+
+To re-enable, either set it back to `{enabled: true}` or remove the variable entirely:
+
+```bash
+cf unset-env JBP_CONFIG_JAVA_CF_ENV
+cf restage
+```
+
+| Variable | Default | Description |
+|----------|---------|-------------|
+| `JBP_CONFIG_JAVA_CF_ENV` | `{enabled: true}` | Enable or disable the framework |
+
+Note: if `java-cfenv*.jar` is already present in the application, the buildpack skips injection automatically — no need to disable explicitly for that case.
+
+Disable when:
+- The application handles `VCAP_SERVICES` manually with custom binding logic
+- The automatic `cloud` profile activation is unwanted
+- Another service binding library conflicts with `java-cfenv`
+
+`{enabled: false}` disables the **whole** framework — both the `VCAP_SERVICES` → Spring property mapping and the `cloud` profile activation. There is no option to disable only the `cloud` profile.
+
+For finer control, bundle a java-cfenv artifact in the application yourself. Because the buildpack backs off whenever a `java-cfenv*.jar` is already present, the app's choice wins:
+
+| App bundles | Property mapping | `cloud` profile |
+|-------------|------------------|-----------------|
+| _(nothing — buildpack injects `java-cfenv-all`)_ | yes | yes |
+| `java-cfenv-all` | yes | yes (app pins the version) |
+| `java-cfenv-boot` | yes | **no** (no `CloudProfileApplicationListener`) |
+| `java-cfenv` (core) | **no** (API only) | **no** |
+
+So an app can include `java-cfenv-boot` to keep property mapping without the `cloud` profile, or the bare `java-cfenv` core to opt out of all automatic behaviour and use the `CfEnv` API directly.
diff --git a/docs/framework-java_memory_assistant.md b/docs/framework-java_memory_assistant.md
new file mode 100644
index 0000000000..f8a2f60594
--- /dev/null
+++ b/docs/framework-java_memory_assistant.md
@@ -0,0 +1,125 @@
+# Java Memory Assistant Framework
+The Java Memory Assistant is a Java agent (as in `-javaagent`) that creats heap dumps of your application automatically based on preconfigured conditions of memory usage.
+The heap dumps created by the Java Memory Assistant can be analyzed using Java memory profilers that support the `.hprof` format (i.e., virtually all profilers).
+
+
+
+ | Detection Criterion | enabled set in the config/java_memory_assistant.yml |
+
+
+ | Tags | java-memory-assistant=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script.
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by modifying the [`config/java_memory_assistant.yml`][] file in the buildpack fork.
+
+| Name | Description
+| ---- | -----------
+| `enabled` | Whether to enable the Java Memory Assistant framework. By default the agent is turned off.
+| `agent.heap_dump_folder` | The folder on the container's filesystem where heap dumps are created. Default value: `$PWD`
+| `agent.thresholds.` | This configuration allows to define thresholds for every memory area of the JVM. Thresholds can be defined in absolute percentages, e.g., `75%` creates a heap dump at 75% of the selected memory area. It is also possible to specify relative increases and decreases of memory usage: for example, `+5%/2m` will triggera heap dumpo if the particular memory area has increased by `5%` or more over the last two minutes. See below to check which memory areas are supported. Since version `0.3.0`, thresholds can also be specified in terms of absolute values, e.g., `>400MB` (more than 400 MB) or `<=30KB` (30 KB or less); supported memory size units are `KB`, `MB` and `GB`.
+| `agent.check_interval` | The interval between checks. Examples: `1s` (once a second), `3m` (every three minutes), `1h` (once every hour). Default: `5s` (check every five seconds).
+| `agent.max_frequency` | Maximum amount of heap dumps that the Java Memory Assistant is allowed to create in a given amount of time. Examples: `1/30s` (no more than one heap dump every thirty seconds), `2/3m` (up to two heap dumps every three minutes), `1/2h` (one heap dump every two hours). The time interval is checked every time one heap dump *should* be created (based on the specified thresholds), and compared with the timestamps of the previously created heap dumps to make sure that the maximum frequency is not exceeded. Default: `1/1m` (one heap dump per minute). |
+| `agent.log_level` | The log level used by the Java Memory Assistant. Supported values are the same as the Java buildpack's: `DEBUG`, `WARN`, `INFO`, `ERROR` and `FATAL` (the latter is equivalent to `ERROR`). If the `agent.log_level` is not specified, the Java buildpack's log level will be used. |
+| `clean_up.max_dump_count` | Maximum amount of heap dumps that can be stored in the filesystem of the container; when the creation of a new heap dump would cause the threshold to be surpassed, the oldest heap dumps are removed from the file system. Default value: `1` |
+
+### Heap Dump Names
+
+The heap dump filenames will be generated according to the following name pattern:
+
+`-%ts:yyyyMMdd'T'mmssSSSZ%-.hprof`
+
+The timestamp pattern `%ts:yyyyMMdd'T'mmssSSSZ%` is equivalent to the `%FT%T%z` pattern of [strftime](http://www.cplusplus.com/reference/ctime/strftime/) for [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601). The default naming convention matches the [`jvmkill`][] naming convention.
+
+### Supported Memory Areas
+
+| Memory Area | Property Name |
+|------------------------|------------------|
+| Heap | `heap` |
+| Code Cache | `code_cache` |
+| Metaspace | `metaspace` |
+| Compressed Class Space | `compressed_class` |
+| Eden | `eden` |
+| Survivor | `survivor` |
+| Old Generation | `old_gen` |
+| Tenured Gen | `tenured_gen` |
+| CodeHeap 'non-nmethods' | `code_heap.non_nmethods` |
+| CodeHeap 'profiled nmethods' | `code_heap.profiled_nmethods` |
+| CodeHeap 'non-profiled nmethods' | `code_heap.non_profiled_nmethods` |
+
+Different builds and versions of Java Virtual Machines offer different memory areas.
+The list of supported Java Virtual Machines and the respective memory areas can be found in the [Java Memory Assistant documentation](https://github.com/SAP/java-memory-assistant#supported-jvms).
+
+The default values can be found in the [`config/java_memory_assistant.yml`][] file.
+
+### Examples
+
+Enable the Java Memory Assistant with its default settings:
+
+```yaml
+JBP_CONFIG_JAVA_MEMORY_ASSISTANT: '{enabled : true}'
+```
+
+Create heap dumps when the old generation memory pool exceeds 800 MB:
+
+```yaml
+JBP_CONFIG_JAVA_MEMORY_ASSISTANT: '{enabled : true, agent: { thresholds : { old_gen : ">800MB" } } }'
+```
+
+Create heap dumps when the old generation grows by more than 20% in two minutes:
+
+```yaml
+JBP_CONFIG_JAVA_MEMORY_ASSISTANT: '{enabled : true, agent : { thresholds : { old_gen : +20%/2m } } }'
+```
+
+### What are the right thresholds for your application?
+
+Well, it depends.
+The way applications behave in terms of memory management is a direct result of how they are implemented.
+This is much more then case when the applications are under heavy load.
+Thus, there is no "silver bullet" configuration that will serve all applications equally well, and Java Memory Assistant configurations should result from profiling the application under load and then encode the expected memory usage patterns (plus a margin upwards) to detect anomalies.
+
+Nevertheless, a memory area that tends to be particularly interesting to monitor is the so called "old generation" (`old_gen`).
+When instantiated, bjects in the Java heap are allocated in an area called `eden`.
+As garbage collections occur, objects that are not reclaimed become first "survivors" (and belong to the namesake `survivor` memory area) and then eventually become `old_gen`.
+In other words, `old_gen` objects are those that survived multiple garbage collections.
+In contrast, `eden` and `survivor` objects are collectively called "young generation".
+
+Application-wide singletons and pooled objects (threads, connections) are examples of "legitimate" `old_gen` candidates.
+But memory leaks, by their very nature or surviving multiple garbage collections, end up in `old_gen` too.
+Under load that is not too high for the application (and you should find out what it is with load tests and avoid it via rate limiting, e.g., using [route services](https://docs.cloudfoundry.org/services/route-services.html) in front of your application), Java code that allows the JVM to perform efficient memory management tends to have a rather consistent baseline of `old_gen` objects, with most objects being reclaimed as they are still young generation.
+That is, when the `old_gen` grows large with respect to the overall heap, this often signifies some sort of memory leak or, at the very least, suboptimal memory management.
+Notable exceptions to this rule of thumb are applications that use large local caches.
+
+### Making sure heap dumps can be created
+
+The Java Virtual Machine must create heap dumps on a file.
+Unless you are using a `volume service`, it pretty much means that, even if you are uploading the heap dump somewhere else, the heap dump must first land on the ephemeral disk of the container.
+Ephemeral disks have quotas and, if all the space is taken by heap dumps (even incomplete ones!), horrible things are bound to happen to your app.
+
+The maximum size of a heap dump depends on the maximum size of the heap of the Java Virtual Machine.
+Consider increasing the disk quota of your warden/garden container via the `cf scale -k [new size]` using as `new size` to the outcome of the following calculation:
+
+`[max heap size] * [max heap dump count] + 200MB`
+
+The aditional `200MB` is a rule-of-thumb, generous over-approximation of the amount of disk the buildpack and the application therein needs to run.
+If your application requires more filesystem than just a few tens of megabytes, you must increase the additional portion of the disk amount calculation accordingly.
+
+### Where to best store heap dumps?
+
+Heap dumps are created by the Java Virtual Machine on a file on the filesystem mounted by the garden container.
+Normally, the filesystem of a container is ephemeral.
+That is, if your app crashes or it is shut down, the filesystem of its container is gone with it and so are your heap dumps.
+
+To prevent heap dumps from "going down" with the container, you should consider storing them on a `volume service`.
+
+#### Container-mounted volumes
+
+If you are using a filesystem service that mounts persistent volumes to the container, it is enough to name one of the volume services `heap-dump` or tag one volume with `heap-dump`, and the path specified as the `heap_dump_folder` configuration will be resolved against `/-/-`. The default directory convention matches the [`jvmkill`][] directory convention.
+
+[`config/java_memory_assistant.yml`]: ../config/java_memory_assistant.yml
+[`jvmkill`]: jre-open_jdk_jre.md#jvmkill
diff --git a/docs/framework-java_opts.md b/docs/framework-java_opts.md
index 64dafae2f2..1b83d3555b 100644
--- a/docs/framework-java_opts.md
+++ b/docs/framework-java_opts.md
@@ -1,26 +1,177 @@
# Java Options Framework
The Java Options Framework contributes arbitrary Java options to the application at runtime.
-Note: passing Java options using a `JAVA_OPTS` environment variable is not supported and will not work.
- | Detection Criterion | java_opts set in the config/java_opts.yml file |
+ Detection Criterion |
+ java_opts set in the config/java_opts.yml file or the JAVA_OPTS environment variable set |
- | Tags | java-opts |
+ Tags |
+ java-opts |
Tags are printed to standard output by the buildpack detect script
-
## Configuration
-For general information on configuring the buildpack, refer to [Configuration and Extension][].
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
-The framework can be configured by creating or modifying the `config/java_opts.yml` file.
+The framework can be configured by creating or modifying the [`config/java_opts.yml`][] file in the buildpack fork.
| Name | Description
| ---- | -----------
-| `java_opts` | The Java options to use when running the application. All values are used without modification when invoking the JVM. The options are specified as a single YAML scalar in plain style or enclosed in single or double quotes.
+| `from_environment` | Whether to append the value of the `JAVA_OPTS` environment variable to the collection of Java options
+| `java_opts` | The Java options to use when running the application. All values are used without modification when invoking the JVM. The options are specified as a single YAML scalar in plain style or enclosed in single or double quotes.
+
+Any `JAVA_OPTS` from either the config file or environment variables will be specified in the start command after any Java Opts added by other frameworks.
+
+## Runtime variable expansion
+
+Java options are assembled at container start by the buildpack's `profile.d` script
+(`00_java_opts.sh`), then passed to the JVM by the shell-free `javaexec` launcher.
+Because `javaexec` tokenizes `JAVA_OPTS` without invoking a shell, characters such as
+`*`, `&`, `;`, `|`, and `>` are treated as literals — they reach the JVM exactly as
+written.
+
+### Environment variable references
+
+`$VARNAME` and `${VARNAME}` references in **both** `JAVA_OPTS` (env) and `java_opts`
+(config) are expanded at container start against the runtime environment:
+
+```bash
+# $PWD, $HOME, $PORT, and any CF-injected variable all work
+cf set-env my-application JAVA_OPTS '-Dapp.config=$PWD/config/app.properties'
+cf set-env my-application JAVA_OPTS '-Dserver.port=$PORT'
+```
+
+```yaml
+# config/java_opts.yml
+java_opts: '-Xloggc:$PWD/beacon_gc.log -verbose:gc'
+```
+
+### Command substitutions are never executed
+
+`$(...)` and backtick command substitutions are **not** executed. A value such as
+`-Dinject=$(hostname)` reaches the JVM as the literal string `-Dinject=$(hostname)`.
+This is intentional: executing arbitrary commands from a user-supplied option string
+would be a security vulnerability.
+
+### Processor count: `$(nproc)`
+
+The one exception is `-XX:ActiveProcessorCount=$(nproc)`, which the buildpack itself
+emits for JRE vendors that need it. The profile.d script resolves this single known
+token to the actual CPU count before passing the option to the JVM. Any other
+`$(...)` expression passes to the JVM literally.
+
+### Special characters and quoting
+
+Characters that were shell-special under the old `eval`-based launcher (`*`, `&`,
+`;`, `|`, `>`) are now passed to the JVM as literals — no quoting tricks required.
+
+POSIX quoting in the assembled `JAVA_OPTS` string is respected by `javaexec`'s
+tokenizer: a quoted value such as `"-Dfoo=bar baz"` is delivered as the single
+argument `-Dfoo=bar baz`.
+
+| Want to pass to JVM | Write in `JAVA_OPTS` / `java_opts` |
+|---------------------|-------------------------------------|
+| Literal `$PORT` (no expansion) | `\$PORT` |
+| Literal `\` backslash | `\\` |
+| Literal `\\` two backslashes | `\\\\` |
+| Value of `$PORT` at runtime | `$PORT` |
+| Cron expression `0 */7 * * *` | `0 */7 * * *` (no quoting needed) |
+| Space inside one JVM arg | `"-Dfoo=bar baz"` (quote the arg) |
+
+```bash
+# Expand $PORT at runtime
+cf set-env my-application JAVA_OPTS '-Dserver.port=$PORT'
+
+# Literal $PORT — not expanded
+cf set-env my-application JAVA_OPTS '-Dexample.literal=\$PORT'
+
+# Windows-style path — \\ becomes one backslash
+cf set-env my-application JAVA_OPTS '-Dapp.data=C:\\data\\app'
+
+# Cron expression — * is not glob-expanded
+cf set-env my-application JAVA_OPTS '-DcronExpr=0 */7 * * *'
+```
+
+> **Note:** `$` followed by a digit or non-identifier character (e.g. `$1`, `$.`)
+> is left as-is. Undefined variables expand to an empty string.
+
+> **Migrating from the Ruby buildpack?** See
+> [Migrating JAVA_OPTS escaping from the Ruby buildpack](java_opts-ruby-migration.md)
+> for a comparison of the escaping rules.
+
+## Examples
+
+### Configuration File Example
+```yaml
+# config/java_opts.yml
+---
+from_environment: false
+java_opts: -Xloggc:$PWD/beacon_gc.log -verbose:gc
+```
+
+### Environment Variable Override Examples
+
+To override the configuration via the `JBP_CONFIG_JAVA_OPTS` environment variable, use YAML flow style (inline YAML) with curly braces:
+
+**Example 1: Using an array of options (recommended)**
+```bash
+cf set-env my-application JBP_CONFIG_JAVA_OPTS '{ java_opts: ["-Xms256m", "-Xmx1024m", "-XX:+UseG1GC"] }'
+```
+
+Or in the application manifest:
+```yaml
+env:
+ JBP_CONFIG_JAVA_OPTS: '{ java_opts: ["-Xms256m", "-Xmx1024m", "-XX:+UseG1GC"] }'
+```
+
+**Example 2: Disabling from_environment**
+```bash
+cf set-env my-application JBP_CONFIG_JAVA_OPTS '{ from_environment: false, java_opts: ["-Xmx512m"] }'
+```
+
+**Example 3: Multiple JVM options**
+```yaml
+env:
+ JBP_CONFIG_JAVA_OPTS: '{ from_environment: false, java_opts: ["-Xmx512M", "-Xms256M", "-Xss1M", "-XX:MetaspaceSize=157286K", "-XX:MaxMetaspaceSize=314572K"] }'
+```
+
+**Note**: For backward compatibility, a space-separated string is also supported:
+```yaml
+env:
+ JBP_CONFIG_JAVA_OPTS: '{ java_opts: "-Xmx512M -Xms256M" }'
+```
+However, using an array format is recommended for clarity and to avoid parsing ambiguities.
+
+## Allowed Memory Settings
+
+| Argument| Description
+| ------- | -----------
+| `-Xms` | Minimum or initial size of heap.
+| `-Xss` | Size of each thread's stack. **This could effect the total heap size. [JRE Memory]**
+| `-XX:MaxMetaspaceSize` | The maximum size Metaspace can grow to. **This could effect the total heap size. [JRE Memory]**
+| `-XX:MaxPermSize` | The maximum size Permgen can grow to. Only applies to Java 7. **This could effect the total heap size. [JRE Memory]**
+| `-Xmn ` | Maximum size of young generation, known as the eden region.
+| `-XX:+UseGCOverheadLimit` | Use a policy that limits the proportion of the VM's time that is spent in GC before an `java.lang.OutOfMemoryError` error is thrown.
+| `-XX:+UseLargePages` | Use large page memory. For details, see [Java Support for Large Memory Pages].
+| `-XX:-HeapDumpOnOutOfMemoryError` | Dump heap to file when `java.lang.OutOfMemoryError` is thrown.
+| `-XX:HeapDumpPath=` | Path to directory or filename for heap dump.
+| `-XX:LargePageSizeInBytes=` | Sets the large page size used for the Java heap.
+| `-XX:MaxDirectMemorySize=` | Upper limit on the maximum amount of allocatable direct buffer memory. **This could effect the total heap size. [JRE Memory]**
+| `-XX:MaxHeapFreeRatio=` | Maximum percentage of heap free after GC to avoid shrinking.
+| `-XX:MaxNewSize=` | Maximum size of new generation. Since `1.4`, `MaxNewSize` is computed as a function of `NewRatio`.
+| `-XX:MinHeapFreeRatio=` | Minimum percentage of heap free after GC to avoid expansion.
+| `-XX:NewRatio=` | Ratio of old/new generation sizes. 2 is equal to approximately 66%.
+| `-XX:NewSize=` | Default size of new generation.
+| `-XX:OnError=";"` | Run user-defined commands on fatal error.
+| `-XX:ReservedCodeCacheSize=` | _Java 8 Only_ Maximum code cache size. Also know as `-Xmaxjitcodesize`. **This could effect the total heap size. [JRE Memory]**
+| `-XX:SurvivorRatio=` | Ratio of eden/survivor space. Solaris only.
+| `-XX:TargetSurvivorRatio=` | Desired ratio of survivor space used after scavenge.
+[`config/java_opts.yml`]: ../config/java_opts.yml
[Configuration and Extension]: ../README.md#configuration-and-extension
+[Java Support for Large Memory Pages]: http://www.oracle.com/technetwork/java/javase/tech/largememory-jsp-137182.html
+[JRE Memory]: jre-open_jdk_jre.md#memory
diff --git a/docs/framework-jmx-jconsole.png b/docs/framework-jmx-jconsole.png
new file mode 100644
index 0000000000..ed0a52ebb1
Binary files /dev/null and b/docs/framework-jmx-jconsole.png differ
diff --git a/docs/framework-jmx.md b/docs/framework-jmx.md
new file mode 100644
index 0000000000..8d122ccca8
--- /dev/null
+++ b/docs/framework-jmx.md
@@ -0,0 +1,40 @@
+# JMX Framework
+The JMX Framework contributes Java JMX configuration to the application at runtime. **Note:** This framework is only useful in Diego-based containers with SSH access enabled.
+
+
+
+ | Detection Criterion |
+ enabled set in the config/jmx.yml file |
+
+
+ | Tags |
+ jmx=<port> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by creating or modifying the [`config/jmx.yml`][] file in the buildpack fork.
+
+| Name | Description
+| ---- | -----------
+| `enabled` | Whether to enable JMX
+| `port` | The port that the debug agent will listen on. Defaults to `5000`.
+
+## Creating SSH Tunnel
+After starting an application with JMX enabled, an SSH tunnel must be created to the container. To create that SSH container, execute the following command:
+
+```bash
+$ cf ssh -N -T -L :localhost:
+```
+
+The `REMOTE_PORT` should match the `port` configuration for the application (`5000` by default). The `LOCAL_PORT` must match the `REMOTE_PORT`.
+
+Once the SSH tunnel has been created, your JConsole should connect to `localhost:` for JMX access.
+
+
+
+[`config/jmx.yml`]: ../config/jmx.yml
+[Configuration and Extension]: ../README.md#configuration-and-extension
diff --git a/docs/framework-jprofiler_profiler.md b/docs/framework-jprofiler_profiler.md
new file mode 100644
index 0000000000..87a5f5124c
--- /dev/null
+++ b/docs/framework-jprofiler_profiler.md
@@ -0,0 +1,46 @@
+# JProfiler Profiler Framework
+The JProfiler Profiler Framework contributes JProfiler configuration to the application at runtime.
+
+
+
+ | Detection Criterion |
+ enabled set in the config/jprofiler_profiler.yml file |
+
+
+ | Tags |
+ jprofiler-profiler=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by creating or modifying the [`config/jprofiler_profiler.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+| Name | Description
+| ---- | -----------
+| `enabled` | Whether to enable the JProfiler Profiler
+| `port` | The port that the JProfiler Profiler will listen on. Defaults to `8849`.
+| `nowait` | Whether to start process without waiting for JProfiler to connect first. Defaults to `true`.
+| `repository_root` | The URL of the JProfiler Profiler repository index ([details][repositories]).
+| `version` | The version of the JProfiler Profiler to use. Candidate versions can be found in [this listing][].
+
+## Creating SSH Tunnel
+After starting an application with the JProfiler Profiler enabled, an SSH tunnel must be created to the container. To create that SSH container, execute the following command:
+
+```bash
+$ cf ssh -N -T -L :localhost:
+```
+
+The `REMOTE_PORT` should match the `port` configuration for the application (`8849` by default). The `LOCAL_PORT` can be any open port on your computer, but typically matches the `REMOTE_PORT` where possible.
+
+Once the SSH tunnel has been created, your JProfiler Profiler should connect to `localhost:` for debugging.
+
+
+
+[`config/jprofiler_profiler.yml`]: ../config/jprofiler_profiler.yml
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[this listing]: http://download.pivotal.io.s3.amazonaws.com/jprofiler/index.yml
+[repositories]: extending-repositories.md
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
diff --git a/docs/framework-jprofiler_profiler.png b/docs/framework-jprofiler_profiler.png
new file mode 100644
index 0000000000..e7d34c898b
Binary files /dev/null and b/docs/framework-jprofiler_profiler.png differ
diff --git a/docs/framework-jrebel_agent.md b/docs/framework-jrebel_agent.md
new file mode 100644
index 0000000000..a8923c3058
--- /dev/null
+++ b/docs/framework-jrebel_agent.md
@@ -0,0 +1,37 @@
+# JRebel Agent Framework
+
+The JRebel Agent Framework causes an application to be automatically configured to work with [JRebel][]. Pushing any [JRebel Cloud/Remote][] enabled application (containing `rebel-remote.xml`) will automatically download the latest version of [JRebel][] and set it up for use.
+
+
+
+ | Detection Criterion |
+ Existence of a rebel-remote.xml file inside the application archive. This file is present in every application that is configured to use JRebel Cloud/Remote. |
+
+
+ | Tags |
+ jrebel-agent=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+For more information regarding setup and configuration, please refer to the [JRebel with Pivotal Cloud Foundry tutorial][pivotal].
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by modifying the [`config/jrebel_agent.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+| Name | Description
+| ---- | -----------
+| `repository_root` | The URL of the JRebel repository index ([details][repositories]).
+| `version` | The version of JRebel to use. Candidate versions can be found in [this listing][].
+| `enabled` | Whether to activate JRebel (upon the presence of `rebel-remote.xml`) or not.
+
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[`config/jrebel_agent.yml`]: ../config/jrebel_agent.yml
+[JRebel Cloud/Remote]: http://manuals.zeroturnaround.com/jrebel/remoteserver/index.html
+[JRebel]: http://zeroturnaround.com/software/jrebel/
+[pivotal]: http://manuals.zeroturnaround.com/jrebel/remoteserver/pivotal.html
+[repositories]: extending-repositories.md
+[this listing]: http://dl.zeroturnaround.com/jrebel/index.yml
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
diff --git a/docs/framework-luna_security_provider.md b/docs/framework-luna_security_provider.md
new file mode 100644
index 0000000000..bea0a0491e
--- /dev/null
+++ b/docs/framework-luna_security_provider.md
@@ -0,0 +1,123 @@
+# Luna Security Provider Framework
+The Luna Security Provider Framework causes an application to be automatically configured to work with a bound [Luna Security Service][].
+
+
+
+ | Detection Criterion |
+ Existence of a single bound Luna Security Provider service. The existence of an Luna Security service defined by the VCAP_SERVICES payload containing a service name, label or tag with luna as a substring.
+ |
+
+
+ | Tags |
+ luna-security-provider=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## User-Provided Service
+When binding to the Luna Security Provider using a user-provided service, it must have name or tag with `luna` in it. The credential payload can contain the following entries:
+
+| Name | Description
+| ---- | -----------
+| `client` | A hash containing client configuration
+| `servers` | An array of hashes containing server configuration
+| `groups` | An array of hashes containing group configuration
+
+#### Client Configuration
+| Name | Description
+| ---- | -----------
+| `certificate` | A PEM encoded client certificate
+| `private-key` | A PEM encoded client private key
+
+#### Server Configuration
+| Name | Description
+| ---- | -----------
+| `certificate` | A PEM encoded server certificate
+| `name` | A host name or address
+
+#### Group Configuration
+| Name | Description
+| ---- | -----------
+| `label` | The label for the group
+| `members` | An array of group member serial numbers
+
+### Example Credentials Payload
+```
+{
+ "client": {
+ "certificate": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
+ "private-key": "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
+ },
+ "servers": [
+ {
+ "name": "test-host-1",
+ "certificate": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
+ },
+ {
+ "name": "test-host-2",
+ "certificate": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
+ }
+ ],
+ "groups": [
+ {
+ "label": "test-group-1",
+ "members": [
+ "test-serial-number-1",
+ "test-serial-number-2"
+ ]
+ },
+ {
+ "label": "test-group-2",
+ "members": [
+ "test-serial-number-3",
+ "test-serial-number-4"
+ ]
+ }
+ ]
+}
+```
+
+### Creating Credential Payload
+In order to create the credentials payload, you should collapse the JSON payload to a single line and set it like the following
+
+```
+$ cf create-user-provided-service luna -p '{"client":{"certificate":"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----","private-key":"-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"},"servers":[{"name":"test-host-1","certificate":"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"},{"name":"test-host-2","certificate":"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"}],"groups":[{"label":"test-group-1","members":["test-serial-number-1","test-serial-number-2"]},{"label":"test-group-2","members":["test-serial-number-3","test-serial-number-4"]}]}'
+```
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by modifying the [`config/luna_security_provider.yml`][] file in the buildpack. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+| Name | Description
+| ---- | -----------
+| `ha_logging_enabled` | Whether to enable HA logging for the Luna Security Provider. Defaults to `true`.
+| `logging_enabled` | Whether to enable the logging wrapper for the Luna Security Provider. Defaults to `false`.
+| `tcp_keep_alive_enabled` | Whether to enable the client TCP keep alive setting for the Luna Security Provider. Defaults to `false`.
+| `repository_root` | The URL of the Luna Security Provider repository index ([details][repositories]).
+| `version` | Version of the Luna Security Provider to use.
+
+### Configuration Generation
+
+The Luna Security Provider is automatically configured when a service is bound with both `servers` and `groups` keys in the VCAP_SERVICES credentials. The buildpack generates a complete `Chrystoki.conf` configuration file from the service binding information.
+
+#### Default Configuration
+The buildpack includes a default `Chrystoki.conf` template that is embedded at compile time. This provides sensible defaults for Cloud Foundry deployments.
+
+The default configuration file is located in `src/java/resources/files/luna_security_provider/Chrystoki.conf`.
+
+##### Customizing Default Configuration via Fork
+To customize the default Luna Security Provider configuration across all applications using your buildpack:
+
+1. Fork the java-buildpack repository
+2. Modify the configuration file in `src/java/resources/files/luna_security_provider/`
+3. Build and package your custom buildpack
+4. Upload the custom buildpack to your Cloud Foundry foundation
+
+This approach is useful for operators who want to enforce organization-wide Luna Security Provider settings.
+
+[`config/luna_security_provider.yml`]: ../config/luna_security_provider.yml
+[Luna Security Service]: http://www.safenet-inc.com/data-encryption/hardware-security-modules-hsms/
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[repositories]: extending-repositories.md
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
diff --git a/docs/framework-maria_db_jdbc.md b/docs/framework-maria_db_jdbc.md
index f15947299b..635767f92f 100644
--- a/docs/framework-maria_db_jdbc.md
+++ b/docs/framework-maria_db_jdbc.md
@@ -4,18 +4,18 @@ The MariaDB JDBC Framework causes a JDBC driver JAR to be automatically download
| Detection Criterion |
- Existence of a single bound MariaDB or MySQL service and no provided MariaDB or MySQL JDBC JAR.
+ | Existence of a single bound MariaDB or MySQL service and NO provided MariaDB or MySQL JDBC jar.
- - Existence of a MariaDB service is defined as the
VCAP_SERVICES payload containing a service who's name, label or tag has mariadb as a substring.
- - Existence of a MySQL service is defined as the
VCAP_SERVICES payload containing a service who's name, label or tag has mysql as a substring.
- - Existence of a MariaDB JDBC JAR is defined as the application containing a JAR who's name matches mariadb-java-client*.jar
- - Existence of a MySQL JDBC JAR is defined as the application containing a JAR who's name matches mysql-connector-java*.jar
+ - Existence of a MariaDB service is defined as the
VCAP_SERVICES payload containing a service whose name, label or tag has mariadb as a substring.
+ - Existence of a MySQL service is defined as the
VCAP_SERVICES payload containing a service whose name, label or tag has mysql as a substring.
+ - Existence of a MariaDB JDBC jar is defined as the application containing a JAR whose name matches
mariadb-java-client*.jar
+ - Existence of a MySQL JDBC jar is defined as the application containing a JAR whose name matches
mysql-connector-j*.jar
|
| Tags |
- maria-db-jdbc=<version> |
+ maria-db-jdbc=<version> |
Tags are printed to standard output by the buildpack detect script
@@ -24,9 +24,9 @@ Tags are printed to standard output by the buildpack detect script
Users may optionally provide their own MariaDB or MySQL service. A user-provided MariaDB or MySQL service must have a name or tag with `mariadb` or `mysql` in it so that the MariaDB JDBC Framework will automatically download the JDBC driver JAR and place it on the classpath.
## Configuration
-For general information on configuring the buildpack, refer to [Configuration and Extension][].
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
-The framework can be configured by modifying the [`config/maria_db_jdbc.yml`][] file. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+The framework can be configured by modifying the [`config/maria_db_jdbc.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
| Name | Description
| ---- | -----------
diff --git a/docs/framework-metric_writer.md b/docs/framework-metric_writer.md
new file mode 100644
index 0000000000..aeaaff0a5a
--- /dev/null
+++ b/docs/framework-metric_writer.md
@@ -0,0 +1,44 @@
+# Metric Writer Framework
+The Metric Writer Framework causes an application to be automatically configured to add Cloud Foundry-specific Micrometer tags.
+
+
+
+ | Detection Criterion |
+ Existence of a micrometer-core*.jar file in the application directory |
+
+
+ | Tags |
+ metric-writer-reconfiguration=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+The Metric Writer Framework adds a set of CloudFoundry-specific Micrometer tags to any Micrometer metric that does not already contain the keys. The values of these tags can be explicitly configured via environment variables otherwise they default to values extracted from the standard Cloud Foundry runtime environment.
+
+| Tag | Environment Variable | Default
+| --- | ---------------------| -----------
+| `cf.account` | `CF_APP_ACCOUNT` | `$VCAP_APPLICATION / cf_api`
+| `cf.application` | `CF_APP_APPLICATION`| `$VCAP_APPLICATION / application_name / frigga:name`
+| `cf.cluster` | `CF_APP_CLUSTER` | `$VCAP_APPLICATION / application_name / frigga:cluster`
+| `cf.version` | `CF_APP_VERSION` | `$VCAP_APPLICATION / application_name / frigga:revision`
+| `cf.instance.index` | `CF_APP_INSTANCE_INDEX` | `$CF_INSTANCE_INDEX`
+| `cf.organization` | `CF_APP_ORGANIZATION` | `$VCAP_APPLICATION / organization_name`
+| `cf.space` | `CF_APP_SPACE` | `$VCAP_APPLICATION / space_name`
+
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by modifying the [`config/metric_writer.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+| Name | Description
+| ---- | -----------
+| `enabled` | Whether to attempt metric augmentation
+| `repository_root` | The URL of the Metric Writer repository index ([details][repositories]).
+| `version` | The version of Metric Writer to use. Candidate versions can be found in [this listing][].
+
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[`config/metric_writer.yml`]: ../config/metric_writer.yml
+[repositories]: extending-repositories.md
+[this listing]: https://java-buildpack.cloudfoundry.org/metric-writer/index.yml
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
diff --git a/docs/framework-multi_buildpack.md b/docs/framework-multi_buildpack.md
new file mode 100644
index 0000000000..3c99af0fdb
--- /dev/null
+++ b/docs/framework-multi_buildpack.md
@@ -0,0 +1,51 @@
+# Multiple Buildpack Framework
+
+## ⚠️ IMPORTANT NOTE - NO LONGER NEEDED
+
+**This framework is NOT implemented in the Go-based Java Buildpack** because multi-buildpack support is now **built-in natively** to Cloud Foundry's buildpack lifecycle.
+
+The Go-based Java Buildpack uses the [cloudfoundry/libbuildpack](https://github.com/cloudfoundry/libbuildpack) library which automatically handles multi-buildpack scenarios without requiring a separate framework.
+
+**For Ruby Buildpack Users**: This framework was needed in the original Ruby-based Java Buildpack (pre-v4.x) to support multi-buildpack deployments. If you're using the Go-based buildpack, **you don't need to configure anything** - multi-buildpack support works automatically.
+
+---
+
+## Background (Historical)
+
+The Multiple Buildpack Framework (in the Ruby buildpack) enabled the Java Buildpack to act as the final buildpack in a multiple buildpack deployment. It read the contributions of other, earlier buildpacks and incorporated them into its standard staging.
+
+
+
+ | Detection Criterion |
+ Existence of buildpack contribution directories (typically /tmp/<RANDOM>/deps/<INDEX> containing a config.yml file. |
+
+
+ | Tags |
+ multi-buildpack=<BUILDPACK_NAME>,... |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## Multiple Buildpack Integration API
+When the Java Buildpack acts as the final buildpack in a multiple buildpack deployment it honors the following core contract integration points.
+
+| Integration Point | Buildpack Usage
+| ----------------- | ---------------
+| `/bin` | An existing `/bin` directory contributed by a non-final buildpack will be added to the `$PATH` of the application as it executes
+| `/lib` | An existing `/lib` directory contributed by a non-final buildpack will be added to the `$LD_LIBRARY_PATH` of the application as it executes
+
+In addition to the core contract, the Java Buildpack defines the following keys in `config.yml` as extension points for contributing to the application. **All keys are optional, and all paths are absolute.**
+
+| Key | Type | Description
+| --- | ---- | -----------
+| `additional_libraries` | `[ path ]` | An array of absolute paths to libraries will be added to the application's classpath
+| `environment_variables` | `{ string, ( path \| string ) }` | A hash of string keys to absolute path or string values that will be added as environment variables
+| `extension_directories` | `[ path ]` | An array of absolute paths to directories containing JRE extensions
+| `java_opts.agentpaths` | `[ path ]` | An array of absolute paths to libraries that will be added as agents
+| `java_opts.agentpaths_with_props` | `{ path, { string, string } }` | A nested hash with absolute paths keys and hashes of string keys and string values as a value that will be added as agents with properties
+| `java_opts.bootclasspath_ps` | `[ path ]` | An array of absolute paths that will be added to the application's bootclasspath
+| `java_opts.javaagents` | `[ path ]` | An array of absolute paths that will be added as javaagents
+| `java_opts.preformatted_options` | `[ string ]` | An array of strings that will be added as options without modification
+| `java_opts.options` | `{ string, ( path \| string ) }` | A hash of string keys to absolute path or string values that will be added as options
+| `java_opts.system_properties` | `{ string , ( path \| string ) }` | A hash of string keys to absolute path or string values that will be added as system properties
+| `security_providers` | `[ string ]` | An array of strings to be added to list of security providers
diff --git a/docs/framework-new_relic_agent.md b/docs/framework-new_relic_agent.md
index 204d231be8..bdee9719d8 100644
--- a/docs/framework-new_relic_agent.md
+++ b/docs/framework-new_relic_agent.md
@@ -5,7 +5,7 @@ The New Relic Agent Framework causes an application to be automatically configur
| Detection Criterion | Existence of a single bound New Relic service.
- - Existence of a New Relic service is defined as the
VCAP_SERVICES payload containing a service who's name, label or tag has newrelic as a substring.
+ - Existence of a New Relic service is defined as the
VCAP_SERVICES payload containing a service who's name, label or tag has newrelic as a substring.
|
@@ -23,21 +23,63 @@ The credential payload of the service may contain the following entries:
| Name | Description
| ---- | -----------
-| `licenseKey` | The license key to use when authenticating
+| `license_key` | (Optional) Either this credential or `licenseKey` must be provided. If both are provided then the value for `license_key` will always win. The license key to use when authenticating.
+| `licenseKey` | (Optional) As above.
+| `***` | (Optional) Any additional entries will be applied as a system property appended to `-Dnewrelic.config.` to allow full configuration of the agent.
## Configuration
-For general information on configuring the buildpack, refer to [Configuration and Extension][].
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
-The framework can be configured by modifying the [`config/new_relic_agent.yml`][] file. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+The framework can be configured by modifying the [`config/new_relic_agent.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
| Name | Description
| ---- | -----------
| `repository_root` | The URL of the New Relic repository index ([details][repositories]).
| `version` | The version of New Relic to use. Candidate versions can be found in [this listing][].
+| `extensions.repository_root` | The URL of the Extensions repository index ([details][repositories]).
+| `extensions.version` | The version of the Extensions to use. Candidate versions can be found in the the repository that you have created to house the Extensions.
+
+### Extensions
+
+Custom New Relic instrumentation in the form of [Extension XML Files][] (or JARs) may be provided via a custom repository.
+
+Example in a manifest.yml
+
+```yaml
+env:
+ JBP_CONFIG_NEW_RELIC_AGENT: '{ extensions: { repository_root: "http://repository..." } }'
+```
+
+The artifacts that the repository provides must be in TAR format and must include the extension files in a directory, with a structure like:
+
+```
+extensions
+|- my-extension.xml
+|- my-other-extension.jar
+|...
+```
+
+### Additional Configuration
+
+#### Default Configuration
+The buildpack includes a default `newrelic.yml` configuration file that is embedded at compile time. This provides sensible defaults for Cloud Foundry deployments.
+
+The default configuration file is located in `src/java/resources/files/new_relic_agent/newrelic.yml`.
+
+##### Customizing Default Configuration via Fork
+To customize the default New Relic configuration across all applications using your buildpack:
+
+1. Fork the java-buildpack repository
+2. Modify the configuration file in `src/java/resources/files/new_relic_agent/`
+3. Build and package your custom buildpack
+4. Upload the custom buildpack to your Cloud Foundry foundation
+
+This approach is useful for operators who want to enforce organization-wide New Relic settings.
[Configuration and Extension]: ../README.md#configuration-and-extension
[`config/new_relic_agent.yml`]: ../config/new_relic_agent.yml
[New Relic Service]: https://newrelic.com
[repositories]: extending-repositories.md
-[this listing]: http://download.pivotal.io.s3.amazonaws.com/new-relic/index.yml
+[this listing]: https://download.run.pivotal.io/new-relic/index.yml
[version syntax]: extending-repositories.md#version-syntax-and-ordering
+[Extension XML Files]: https://docs.newrelic.com/docs/agents/java-agent/custom-instrumentation/java-instrumentation-xml
diff --git a/docs/framework-open_telemetry_javaagent.md b/docs/framework-open_telemetry_javaagent.md
new file mode 100644
index 0000000000..26706700cd
--- /dev/null
+++ b/docs/framework-open_telemetry_javaagent.md
@@ -0,0 +1,50 @@
+# OpenTelemetry Javaagent
+
+The OpenTelemetry Javaagent buildpack framework will cause an application to be automatically instrumented
+with the [OpenTelemetry Javaagent Instrumentation](https://github.com/open-telemetry/opentelemetry-java-instrumentation).
+
+Data will be sent directly to the OpenTelemetry Collector.
+
+
+
+ | Detection Criterion |
+ Existence of a bound service containing the string otel-collector |
+
+
+ | Tags |
+ opentelemetry-javaagent=<version> |
+
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## User-Provided Service
+
+Users are currently expected to `create-user-provided-service` (cups) of the collector
+and bind it to their application. The service MUST contain the string `otel-collector`.
+
+For example, to create a service named `otel-collector` that represents an environment named `cf-demo`, you could use the following commands:
+
+```
+$ cf cups otel-collector -p '{"otel.exporter.otlp.endpoint" : "https://my-collector-endpoint", "otel.exporter.otlp.headers" : "authorization=Basic SOMEBAS64STRING","otel.exporter.otlp.protocol" : "grpc", "otel.traces.exporter" : "otlp", "otel.metrics.exporter" : "otlp", "otel.resource.attributes": "deployment.environment=cf-demo"}'
+$ cf bind-service myApp otel-collector
+$ cf restage myApp
+```
+
+Additional configuration options for the Agent can be found [here](https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/#configuring-with-environment-variables)
+
+### Choosing a version
+
+Most users should skip this and simply use the latest version of the agent available (the default).
+To override the default and choose a specific version, you can use the `JBP_CONFIG_*` mechanism
+and set the `JBP_CONFIG_OPENTELEMETRY_JAVAAGENT` environment variable for your application.
+
+For example, to use version 1.27.0 of the OpenTelemetry Javaagent Instrumentation, you
+could run:
+```
+$ cf set-env testapp JBP_CONFIG_OPENTELEMETRY_JAVAAGENT '{version: 1.27.0}'
+```
+
+# Additional Resources
+
+* [OpenTelemetry Javaagent Instrumentation](https://github.com/open-telemetry/opentelemetry-java-instrumentation) on GitHub
diff --git a/docs/framework-ordering.md b/docs/framework-ordering.md
new file mode 100644
index 0000000000..d6158fffbe
--- /dev/null
+++ b/docs/framework-ordering.md
@@ -0,0 +1,154 @@
+# Framework Ordering and JAVA_OPTS Priority
+
+## Overview
+
+This document defines the execution order for Java Buildpack frameworks, based on the Ruby buildpack's `config/components.yml` (lines 40-83).
+
+**Critical**: Framework order matters because:
+1. Some frameworks modify JVM bootstrap behavior (e.g., Container Security Provider)
+2. Some frameworks require native library loading before security modifications (e.g., JRebel)
+3. User-defined JAVA_OPTS should override framework defaults (JavaOpts framework runs last)
+
+## Framework Order (Ruby Buildpack `components.yml` Lines 44-82)
+
+**IMPORTANT**: These line numbers from the Ruby buildpack directly map to execution priority.
+
+```
+Line | Framework Name | Priority | Notes
+-----|----------------------------------------|----------|------------------------------------------
+44 | MultiBuildpack | 10 | Allows overrides from earlier buildpacks
+45 | AppDynamicsAgent | 11 | APM agent
+46 | AspectjWeaverAgent | 12 | AOP agent
+47 | AzureApplicationInsightsAgent | 13 | APM agent
+48 | CheckmarxIastAgent | 14 | Security agent
+49 | ClientCertificateMapper | 15 | Security
+50 | ContainerCustomizer | 16 | Container modifications
+51 | ContainerSecurityProvider | 17 | ⚠️ Modifies bootclasspath & security
+52 | ContrastSecurityAgent | 18 | Security agent
+53 | DatadogJavaagent | 19 | APM agent
+54 | Debug | 20 | Debug agent (-agentlib:jdwp)
+55 | DynatraceOneAgent | 21 | APM agent
+56 | ElasticApmAgent | 22 | APM agent
+57 | GoogleStackdriverDebugger | 23 | Debugger (commented out)
+58 | GoogleStackdriverProfiler | 24 | Profiler
+59 | IntroscopeAgent | 25 | APM agent
+60 | JacocoAgent | 26 | Code coverage agent
+61 | JavaCfEnv | 27 | Environment configuration
+62 | JavaMemoryAssistant | 28 | Memory management
+63 | Jmx | 29 | JMX configuration
+64 | JprofilerProfiler | 30 | Profiler
+65 | JrebelAgent | 31 | ⚠️ Native agent, runs AFTER CSP
+66 | LunaSecurityProvider | 32 | Security provider
+67 | MariaDbJDBC | 33 | JDBC driver
+68 | MetricWriter | 34 | Metrics
+69 | NewRelicAgent | 35 | APM agent
+70 | OpenTelemetryJavaagent | 36 | Observability agent
+71 | PostgresqlJDBC | 37 | JDBC driver
+72 | RiverbedAppinternalsAgent | 38 | APM agent
+73 | SealightsAgent | 39 | Security agent
+74 | SeekerSecurityProvider | 40 | Security provider
+75 | SpringAutoReconfiguration | 41 | Spring framework
+76 | SplunkOtelJavaAgent | 42 | Observability agent
+77 | SpringInsight | 43 | Spring monitoring
+78 | SkyWalkingAgent | 44 | APM agent
+79 | YourKitProfiler | 45 | Profiler
+80 | JavaSecurity | 47 | Security configuration
+81 | JavaOpts | 99 | ⚠️ USER-DEFINED OPTS (ALWAYS LAST)
+```
+
+## Go Buildpack Implementation
+
+In the Go buildpack, we implement this ordering using numbered `.opts` files:
+
+### Directory Structure
+```
+$DEPS_DIR//
+ java_opts/
+ 05_jre.opts # JRE base options (memory calculator, JVMKill, etc.)
+ 17_container_security.opts # Container Security Provider (Line 51)
+ 20_debug.opts # Debug framework (Line 54)
+ 29_jmx.opts # JMX framework (Line 63)
+ 31_jrebel.opts # JRebel agent (Line 65)
+ 99_user_java_opts.opts # User-defined JAVA_OPTS (Line 82, ALWAYS LAST)
+```
+
+Where `` is the buildpack index (0 for standalone usage, or the position in multi-buildpack chain).
+
+### Assembly at Runtime
+
+A single `profile.d/00_java_opts.sh` script reads all `.opts` files in order:
+
+```bash
+#!/bin/bash
+export JAVA_OPTS=""
+for opts_file in $DEPS_DIR//java_opts/*.opts; do
+ if [ -f "$opts_file" ]; then
+ JAVA_OPTS="$JAVA_OPTS $(cat $opts_file)"
+ fi
+done
+export JAVA_OPTS
+```
+
+This ensures:
+1. **Explicit ordering** via numbered filenames (shell glob sorts numerically)
+2. **Container Security Provider runs BEFORE JRebel** (07 < 20)
+3. **User JAVA_OPTS override everything** (99 runs last)
+
+> **Note (safe expansion):** the snippet above is simplified. The real
+> `00_java_opts.sh` does **not** use `eval`. It expands only `$VAR` / `${VAR}`
+> references in `.opts` content via a pure-bash expander, so embedded command
+> substitutions (`$(...)`, backticks) are never executed. The one trusted
+> substitution the buildpack emits, `-XX:ActiveProcessorCount=$(nproc)`, is
+> resolved explicitly at runtime; any other surviving `$(...)` triggers a
+> warning. At launch the JVM is started through the shell-free `javaexec`
+> launcher (`$DEPS_DIR//bin/javaexec`), which tokenizes `JAVA_OPTS`
+> without re-invoking a shell, rather than `eval "exec java $JAVA_OPTS"`.
+
+## Critical Ordering Dependencies
+
+### Container Security Provider (Priority 17, Line 51)
+- **Must run EARLY** because it modifies:
+ - `-Xbootclasspath/a:` (prepends JAR to bootstrap classpath)
+ - `-Djava.security.properties=` (overrides security configuration)
+- These settings affect JVM initialization and security subsystem
+
+### JRebel Agent (Priority 31, Line 65)
+- **Must run AFTER Container Security Provider** because:
+ - JRebel is a native agent (`-agentpath:`)
+ - Requires access to JVM internals that may be restricted by security providers
+ - If security settings change AFTER JRebel loads, JRebel crashes with:
+ ```
+ JRebel-JVMTI [FATAL] A fatal error occurred while processing the base Java classes
+ Caused by: java.security.NoSuchAlgorithmException: SHA MessageDigest not available
+ ```
+
+### JavaOpts (Priority 99)
+- **Must run LAST** to allow users to override any framework-contributed JAVA_OPTS
+- Example: User sets `-Xmx2g` to override memory calculator's `-Xmx768M`
+
+## Adding New Frameworks
+
+When implementing a new framework that contributes JAVA_OPTS:
+
+1. **Determine priority** based on Ruby buildpack ordering (see table above)
+2. **Write `.opts` file** with appropriate priority prefix:
+ ```go
+ optsContent := fmt.Sprintf("-javaagent:%s", agentPath)
+ optsFile := fmt.Sprintf("%02d_%s.opts", priority, frameworkName)
+ f.context.Stager.WriteFile(filepath.Join("java_opts", optsFile), optsContent)
+ ```
+3. **Update this document** with the new framework's priority
+
+## Why Not Use Profile.d Script Per Framework?
+
+**Problem**: Profile.d scripts execute sequentially at runtime in **alphabetical order**. This creates timing issues:
+- `01_jrebel.sh` runs, sets `-agentpath:`
+- `container_security_provider.sh` runs, appends `-Xbootclasspath/a:`
+- JVM sees options in this order, but CSP needs to initialize BEFORE JRebel
+
+**Solution**: Collect all options BEFORE JVM starts, assemble in correct priority order, then export as single `JAVA_OPTS` variable.
+
+## References
+
+- Ruby buildpack: `/home/ramonskie/workspace/tmp/orig-java/config/components.yml` lines 40-83
+- Go buildpack framework registry: `src/java/frameworks/framework.go` lines 54-113
diff --git a/docs/framework-play_framework_auto_reconfiguration.md b/docs/framework-play_framework_auto_reconfiguration.md
deleted file mode 100644
index d84cc326b3..0000000000
--- a/docs/framework-play_framework_auto_reconfiguration.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# Play Framework Auto Reconfiguration Framework
-The Play Framework Auto Reconfiguration Framework causes an application to be automatically reconfigured to work with configured cloud services.
-
-
-
- | Detection Criterion |
- An application is a Play Framework application |
-
-
- | Tags |
- play-framework-auto-reconfiguration=<version> |
-
-
-Tags are printed to standard output by the buildpack detect script
-
-## Configuration
-For general information on configuring the buildpack, refer to [Configuration and Extension][].
-
-The framework can be configured by modifying the [`config/play_framework_auto_reconfiguration.yml`][] file. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
-
-
-| Name | Description
-| ---- | -----------
-| `repository_root` | The URL of the Auto Reconfiguration repository index ([details][repositories]).
-| `version` | The version of Auto Reconfiguration to use. Candidate versions can be found in [this listing][].
-
-[Configuration and Extension]: ../README.md#configuration-and-extension
-[`config/play_framework_auto_reconfiguration.yml`]: ../config/config/play_framework_auto_reconfiguration.yml
-[repositories]: extending-repositories.md
-[this listing]: http://download.pivotal.io.s3.amazonaws.com/auto-reconfiguration/index.yml
-[version syntax]: extending-repositories.md#version-syntax-and-ordering
diff --git a/docs/framework-play_framework_jpa_plugin.md b/docs/framework-play_framework_jpa_plugin.md
deleted file mode 100644
index b8380d699f..0000000000
--- a/docs/framework-play_framework_jpa_plugin.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# Play Framework JPA Plugin Framework
-The Play Framework JPA Plugin Framework causes an application to be automatically reconfigured to work with configured cloud services.
-
-
-
- | Detection Criterion |
-
-
- - An application is a Play Framework 2.0 application
- - An application uses the play-java-jpa plugin
-
- |
-
-
- | Tags |
- play-framework-jpa-plugin=<version> |
-
-
-Tags are printed to standard output by the buildpack detect script
-
-## Configuration
-For general information on configuring the buildpack, refer to [Configuration and Extension][].
-
-The framework can be configured by modifying the [`config/play_framework_jpa_plugin.yml`][] file. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
-
-| Name | Description
-| ---- | -----------
-| `repository_root` | The URL of the Play Framework JPA Plugin repository index ([details][repositories]).
-| `version` | The version of the Play Framework JPA Plugin to use. Candidate versions can be found in [this listing][].
-
-[Configuration and Extension]: ../README.md#configuration-and-extension
-[`config/play_framework_jpa_plugin.yml`]: ../config/play_framework_jpa_plugin.yml
-[repositories]: extending-repositories.md
-[this listing]: http://download.pivotal.io.s3.amazonaws.com/play-jpa-plugin/index.yml
-[version syntax]: extending-repositories.md#version-syntax-and-ordering
diff --git a/docs/framework-postgresql_jdbc.md b/docs/framework-postgresql_jdbc.md
index 01043388e6..bff4a17844 100644
--- a/docs/framework-postgresql_jdbc.md
+++ b/docs/framework-postgresql_jdbc.md
@@ -6,7 +6,7 @@ The PostgreSQL JDBC Framework causes a JDBC driver JAR to be automatically downl
Detection Criterion |
Existence of a single bound PostgreSQL service and no provided PostgreSQL JDBC JAR.
- - Existence of a PostgreSQL service is defined as the
VCAP_SERVICES payload containing a service who's name, label or tag has postgres as a substring.
+ - Existence of a PostgreSQL service is defined as the
VCAP_SERVICES payload containing a service who's name, label or tag has postgres as a substring.
- Existence of a PostgreSQL JDBC JAR is defined as the application containing a JAR who's name matches postgresql-*.jar
|
@@ -22,9 +22,9 @@ Tags are printed to standard output by the buildpack detect script
Users may optionally provide their own PostgreSQL service. A user-provided PostgreSQL service must have a name or tag with `postgres` in it so that the PostgreSQL JDBC Framework will automatically download the JDBC driver JAR and place it on the classpath.
## Configuration
-For general information on configuring the buildpack, refer to [Configuration and Extension][].
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
-The framework can be configured by modifying the [`config/postgresql_jdbc.yml`][] file. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+The framework can be configured by modifying the [`config/postgresql_jdbc.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
| Name | Description
| ---- | -----------
diff --git a/docs/framework-protect_app_security_provider.md b/docs/framework-protect_app_security_provider.md
new file mode 100644
index 0000000000..d1d4229e92
--- /dev/null
+++ b/docs/framework-protect_app_security_provider.md
@@ -0,0 +1,114 @@
+# ProtectApp Security Provider Framework
+The ProtectApp Security Provider Framework causes an application to be automatically configured to work with a bound [ProtectApp Security Service][].
+
+
+
+ | Detection Criterion |
+ Existence of a single bound ProtectApp Security Provider service. The existence of an ProtectApp Security service defined by the VCAP_SERVICES payload containing a service name, label or tag with protectapp as a substring.
+ |
+
+
+ | Tags |
+ protect-app-security-provider=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## User-Provided Service
+When binding to the ProtectApp Security Provider using a user-provided service, it must have name or tag with `protectapp` in it. The credential payload can contain the following entries:
+
+| Name | Description
+| ---- | -----------
+| `client` | The client configuration
+| `trusted_certificates` | An array of certs containing trust information
+| `NAE_IP.1` | A list of KeySecure server ips or hostnames to be used
+| `***` | (Optional) Any additional entries will be applied as a system property appended to `-Dcom.ingrian.security.nae.` to allow full configuration of the library.
+
+#### Client Configuration
+| Name | Description
+| ---- | -----------
+| `certificate` | A PEM encoded client certificate
+| `private_key` | A PEM encoded client private key
+
+#### Trusted Certs Configuration
+One or more PEM encoded certificate
+
+### Example Credentials Payload
+```
+{
+ "client": {
+ "certificate": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
+ "private_key": "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
+ },
+ "trusted_certificates": [
+ "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
+ "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
+ ],
+ "NAE_IP.1": "192.168.1.25:192.168.1.26"
+}
+```
+
+### Creating Credential Payload
+In order to create the credentials payload, you should collapse the JSON payload to a single line and set it like the following
+
+```
+$ cf create-user-provided-service protectapp -p '{"client":{"certificate":"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----","private_key":"-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"},"trusted_certificates":["-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----","-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"],"NAE_IP.1":"192.168.1.25:192.168.1.26"}'
+```
+
+You may want to use a file for this
+
+Note the client portion is very exacting and needs line breaks in the body every 64 characters.
+
+1. The file must contain:
+`-----BEGIN CERTIFICATE-----`
+on a separate line (i.e. it must be terminated with a newline).
+1. Each line of "gibberish" must be 64 characters wide.
+1. The file must end with:
+`-----END CERTIFICATE-----`
+and also be terminated with a newline.
+1. Don't save the cert text with Word. It must be in ASCII.
+1. Don't mix DOS and UNIX style line terminations.
+
+So, here are a few steps you can take to normalize your certificate:
+
+1. Run it through `dos2unix`
+`$ dos2unix cert.pem`
+1. Run it through `fold`
+`$ fold -w 64 cert.pem`
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by modifying the [`config/protect_app_security_provider.yml`][] file in the buildpack. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+| Name | Description
+| ---- | -----------
+| `repository_root` | The URL of the ProtectApp Security Provider repository index ([details][repositories]).
+| `version` | Version of the ProtectApp Security Provider to use.
+
+### Additional Configuration
+
+#### Default Configuration
+The buildpack includes a default `IngrianNAE.properties` configuration file that is embedded at compile time. This provides sensible defaults for Cloud Foundry deployments.
+
+The default configuration file is located in `src/java/resources/files/protect_app_security_provider/IngrianNAE.properties`.
+
+##### Customizing Default Configuration via Fork
+To customize the default ProtectApp Security Provider configuration across all applications using your buildpack:
+
+1. Fork the java-buildpack repository
+2. Modify the configuration file in `src/java/resources/files/protect_app_security_provider/`
+3. Build and package your custom buildpack
+4. Upload the custom buildpack to your Cloud Foundry foundation
+
+This approach is useful for operators who want to enforce organization-wide ProtectApp Security Provider settings.
+
+All ProtectApp configuration can also be provided via:
+- System properties passed through VCAP_SERVICES credentials (using the `-Dcom.ingrian.security.nae.*` prefix)
+- The credentials payload as documented above
+
+[`config/protect_app_security_provider.yml`]: ../config/protect_app_security_provider.yml
+[ProtectApp Security Service]: https://safenet.gemalto.com/data-encryption/protectapp-application-protection/
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[repositories]: extending-repositories.md
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
diff --git a/docs/framework-riverbed_appinternals_agent.md b/docs/framework-riverbed_appinternals_agent.md
new file mode 100644
index 0000000000..f0012a01f6
--- /dev/null
+++ b/docs/framework-riverbed_appinternals_agent.md
@@ -0,0 +1,58 @@
+# Riverbed Appinternals Agent Framework
+The Riverbed Appinternals Agent Framework causes an application to be bound with a Riverbed Appinternals service instance.
+
+
+
+ | Detection Criterion | Existence of a single bound Riverbed Appinternals agent service. The existence of an agent service is defined by the VCAP_SERVICES payload containing a service name, label or tag with appinternals as a substring.
+ |
+
+
+ | Tags |
+ riverbed-appinternals-agent=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## User-Provided Service
+When binding Appinternals using a user-provided service, it must have appinternals as substring. The credential payload can contain the following entries:
+
+| Name | Description
+| ---- | -----------
+| `rvbd_dsa_port` | (Optional)The AppInternals agent (DSA) port (default 2111).
+| `rvbd_agent_port` | (Optional) The AppInternals agent socket port (default 7073).
+| `rvbd_moniker` | (Optional) A custom name for the application (default supplied by agent process discovery).
+
+**NOTE**
+
+Change `rvbd_dsa_port` and `rvbd_agent_port` only if there is a port conflict
+
+### Example: Creating Riverbed Appinternals User-Provided Service Payload
+
+```
+cf cups spring-music-appinternals -p '{"rvbd_dsa_port":"9999","rvbd_moniker":"my_app"}'
+cf bind-service spring-music spring-music-appinternals
+```
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by modifying the [`config/riverbed_appinternals_agent.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+| Name | Description
+| ---- | -----------
+| `repository_root` | The URL of the Riverbed Appinternals agent repository index ([details][repositories]).
+| `version` | The version of the Riverbed Appinternals agent to use.
+
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[repositories]: extending-repositories.md
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
+[`config/riverbed_appinternals_agent.yml`]: ../config/riverbed_appinternals_agent.yml
+
+
+**NOTE**
+
+If the Riverbed Service Broker's version is greater than or equal to 10.20, the buildpack will instead download Riverbed AppInternals agent from Riverbed Service Broker and will fall back to using `repository_root` in [`config/riverbed_appinternals_agent.yml`][] only if Service Broker failed to serve the Agent artifact.
+
+**NOTE**
+
+If the Rivered verstion is 10.21.9 or later, the buildpack will load the profiler normally, instead of from the Service Broker. This allows for creating multiple offline buildpacks containing different versions.
diff --git a/docs/framework-sealights_agent.md b/docs/framework-sealights_agent.md
new file mode 100644
index 0000000000..235254b8a9
--- /dev/null
+++ b/docs/framework-sealights_agent.md
@@ -0,0 +1,54 @@
+# Sealights Agent Framework
+The Sealights Agent Framework causes an application to be automatically configured to work with [Sealights Service][].
+
+
+
+ | Detection Criterion | Existence of a single bound sealights service. The existence of a sealights service defined by the VCAP_SERVICES payload containing a service name, label or tag with sealights as a substring.
+ |
+
+
+ | Tags | sealights-agent=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## User-Provided Service
+When binding Sealights using a user-provided service, it must have name or tag with `sealights` in it.
+The credential payload can contain the following entries.
+
+| Name | Description
+| ---- | -----------
+| `token` | A Sealights Agent token
+| `proxy` | Specify a HTTP proxy used to communicate with the Sealights backend. Required when a corporate network prohibits communication to cloud services. The default is to have no proxy configured. This does not inherit from `http_proxy`/`https_proxy` or `http.proxyHost/https.proxyHost`, you must set this specifically if a proxy is needed.
+| `lab_id` | Specify a Sealights [Lab ID][]
+
+All fields above except the agent token may be also specified in the [Configuration Section](#configuration) below.
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by modifying the [`config/sealights_agent.yml`][] file. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+| Name | Description
+| ---- | -----------
+| `build_session_id` | Sealights [Build Session ID][] for the application. Leave blank to use the value embedded in the jar/war artifacts
+| `proxy` | Specify a HTTP proxy used to communicate with the Sealights backend. Required when a corporate network prohibits communication to cloud services. The default is to have no proxy configured. This does not inherit from `http_proxy`/`https_proxy` or `http.proxyHost/https.proxyHost`, you must set this specifically if a proxy is needed.
+| `lab_id` | Specify a Sealights [Lab ID][]
+| `auto_upgrade` | Enable/disable agent auto-upgrade. Off by default
+| `version` | The version of Auto-reconfiguration to use. Candidate versions can be found in [this listing][]. If auto_upgrade is turned on, a different version may be downloaded and used at runtime
+
+Configuration settings will take precedence over the ones specified in the [User-Provided Service](#user-provided-service), if those are defined.
+
+## Troubleshooting and Support
+
+For additional documentation and support, visit the official [Sealights Java agents documentation] page
+
+[`config/sealights_agent.yml`]: ../config/sealights_agent.yml
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[repositories]: extending-repositories.md
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
+[Sealights Service]: https://www.sealights.io
+[Build Session ID]: https://sealights.atlassian.net/wiki/spaces/SUP/pages/3473472/Using+Java+Agents+-+Generating+a+session+ID
+[Lab ID]: https://sealights.atlassian.net/wiki/spaces/SUP/pages/762413124/Using+Java+Agents+-+Running+Tests+in+Parallel+Lab+Id
+[this listing]: https://agents.sealights.co/pcf/index.yml
+[Sealights Java agents documentation]: https://sealights.atlassian.net/wiki/spaces/SUP/pages/3014685/SeaLights+Java+agents
diff --git a/docs/framework-seeker_security_provider.md b/docs/framework-seeker_security_provider.md
new file mode 100644
index 0000000000..d4af7dd408
--- /dev/null
+++ b/docs/framework-seeker_security_provider.md
@@ -0,0 +1,24 @@
+# Seeker Security Provider Framework
+The Seeker Security Provider Framework causes an application to be bound with a [Seeker Security Provider][s] service instance.
+
+
+
+ | Detection Criterion | Existence of a single bound Seeker Security Provider service. The existence of a provider service is defined by the VCAP_SERVICES payload containing a service name, label or tag with seeker as a substring.
+ |
+
+
+ | Tags |
+ seeker-service-provider |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## User-Provided Service
+When binding Appinternals using a user-provided service, it must have seeker as substring. The credential payload must contain the following entries:
+
+| Name | Description
+| ---- | -----------
+| `seeker_server_url` | The fully qualified URL of a Synopsys Seeker Server (e.g. `https://seeker.example.com`)
+
+**NOTE**
+In order to use this integration, the Seeker Server version must be at least `2019.08` or later.
diff --git a/docs/framework-sky_walking_agent.md b/docs/framework-sky_walking_agent.md
new file mode 100644
index 0000000000..b0cd2f84d4
--- /dev/null
+++ b/docs/framework-sky_walking_agent.md
@@ -0,0 +1,49 @@
+# SkyWalking Agent Framework
+The SkyWalking Agent Framework causes an application to be automatically configured to work with a bound [SkyWalking Service][] **Note:** This framework is disabled by default.
+
+
+
+ | Detection Criterion | Existence of a single bound SkyWalking service. The existence of an SkyWalking service defined by the VCAP_SERVICES payload containing a service name, label or tag with sky-walking or skywalking as a substring.
+ |
+
+
+ | Tags | sky-walking-agent=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## User-Provided Service
+When binding SkyWalking using a user-provided service, it must have name or tag with `sky-walking` or `skywalking` in it. The credential payload can contain the following entries. **Note:** Credentials marked as "(Optional)" may be required for some versions of the SkyWalking agent. Please see the [SkyWalking Java Agent Configuration Properties][] for the version of the agent used by your application for more details.
+
+| Name | Description
+| ---- | -----------
+| `application-name` | (Optional) The application's name
+| `sample-n-per-3-secs` | (Optional) The number of sampled traces per 3 seconds. Negative number means sample traces as many as possible, most likely 100%
+| `span-limit-per-segment` | (Optional) The max amount of spans in a single segment
+| `ignore-suffix` | (Optional) Ignore the segments if their operation names start with these suffix
+| `open-debugging-class` | (Optional) If true, skywalking agent will save all instrumented classes files in `/debugging` folder.Skywalking team may ask for these files in order to resolve compatible problem
+| `servers` | Server addresses .Examples: Single collector:servers="127.0.0.1:8080",Collector cluster:servers="10.2.45.126:8080,10.2.45.127:7600"
+| `logging-level` | (Optional) Logging level
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by modifying the [`config/sky_walking_agent.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+| Name | Description
+| ---- | -----------
+| `default_application_name` | This is omitted by default but can be added to specify the application name in the SkyWalking dashboard. This can be overridden by an `application-name` entry in the credentials payload. If neither are supplied the default is the `application_name` as specified by Cloud Foundry.
+| `repository_root` | The URL of the SkyWalking repository index ([details][repositories]).
+| `version` | The version of SkyWalking to use. Candidate versions can be found in [this listing][].
+
+### Additional Resources
+
+**Note:** The `resources/sky_walking_agent` directory approach from the Ruby buildpack (2013-2025) is no longer supported. This was a **buildpack-level** feature where teams would fork the java-buildpack repository, add custom files to `resources/sky_walking_agent/`, and package their custom buildpack. The Go buildpack does not package the `resources/` directory.
+
+[`config/sky_walking_agent.yml`]: ../config/sky_walking_agent.yml
+[SkyWalking Java Agent Configuration Properties]: https://github.com/apache/incubator-skywalking/blob/master/docs/en/Deploy-skywalking-agent.md
+[SkyWalking Service]: http://skywalking.io
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[repositories]: extending-repositories.md
+[this listing]: https://download.run.pivotal.io/sky-walking/index.yml
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
diff --git a/docs/framework-splunk_otel_java_agent.md b/docs/framework-splunk_otel_java_agent.md
new file mode 100644
index 0000000000..f6c0bf2a5f
--- /dev/null
+++ b/docs/framework-splunk_otel_java_agent.md
@@ -0,0 +1,64 @@
+# Splunk Distribution of OpenTelemetry Java Instrumentation
+
+This buildpack framework automatically instruments your Java application
+with the [Splunk distribution of OpenTelemetry Java Instrumentation](https://github.com/signalfx/splunk-otel-java)
+to send trace data to Splunk Observability Cloud.
+
+
+
+ | Detection Criterion |
+ Existence of a bound service containing the string splunk-o11y |
+
+
+ | Tags |
+ splunk-otel-java-agent=<version> |
+
+
+
+The buildpack detect script prints tags to standard output.
+
+## User-Provided Service
+
+
+Provide your own "user provided service" (cups) instance and bind
+it to your application.
+
+The service name MUST contain the string `splunk-o11y`.
+
+For example, to create a service named `splunk-o11y` that represents Observability Cloud
+realm `us0` and represents a user environment named `cf-demo`, use the following
+commands:
+
+```
+$ cf cups splunk-o11y -p \
+ '{"splunk.realm": "us0", "splunk.access.token": "", "otel.resource.attributes": "deployment.environment=cf-demo"}'
+$ cf bind-service myApp splunk-o11y
+$ cf restage myApp
+```
+
+Provide the following values using the `credential` field of the service:
+
+| Name | Required? | Description
+|------------------------|-----------| -----------
+| `splunk.access.token` | Yes | Splunk [org access token](https://docs.splunk.com/observability/admin/authentication-tokens/org-tokens.html).
+| `splunk.realm` | Yes | Splunk realm where data will be sent. This is commonly `us0`, `eu0`, and so on. See [Available regions or realms](https://docs.splunk.com/observability/en/get-started/service-description.html#available-regions-or-realms) for more information.
+| `otel.*` or `splunk.*` | Optional | All additional credentials starting with these prefixes are appended to the application's JVM arguments as system properties.
+
+### Choosing a version
+
+To override the default and choose a specific version, use the `JBP_CONFIG_*` mechanism
+and set the `JBP_CONFIG_SPLUNK_OTEL_JAVA_AGENT` environment variable for your application.
+
+For example, to use version 1.16.0 of the Splunk OpenTelemetry Java Instrumentation, run:
+
+```
+$ cf set-env testapp JBP_CONFIG_SPLUNK_OTEL_JAVA_AGENT '{version: 1.16.0}'
+```
+
+In most cases you can use the latest or default version of the agent available.
+
+# Additional Resources
+
+* [Splunk Observability](https://www.splunk.com/en_us/products/observability.html)
+* [Official documentation of the Splunk Java agent](https://docs.splunk.com/observability/en/gdi/get-data-in/application/java/get-started.html)
+* [Splunk Distribution of OpenTelemetry Java](https://github.com/signalfx/splunk-otel-java) on GitHub
diff --git a/docs/framework-spring_auto_reconfiguration.md b/docs/framework-spring_auto_reconfiguration.md
index 8d823a3060..a7a7dfc53b 100644
--- a/docs/framework-spring_auto_reconfiguration.md
+++ b/docs/framework-spring_auto_reconfiguration.md
@@ -1,35 +1,93 @@
-# Spring Auto Reconfiguration Framework
-The Spring Auto Reconfiguration Framework causes an application to be automatically reconfigured to work with configured cloud services.
+# Spring Auto-reconfiguration Framework
+
+---
+## 🛑 CRITICAL DEPRECATION NOTICE 🛑
+
+**THIS FRAMEWORK IS DEPRECATED AND DISABLED BY DEFAULT**
+
+**Status**: Disabled since December 2025
+**Reason**: Spring Cloud Connectors entered maintenance mode in July 2019
+**Action Required**: **MIGRATE TO JAVA-CFENV IMMEDIATELY**
+
+See the **[Migration Guide from Spring Auto-reconfiguration to java-cfenv](spring-auto-reconfiguration-migration.md)** for step-by-step instructions.
+
+---
+
+The Spring Auto-reconfiguration Framework causes an application to be automatically reconfigured to work with configured cloud services.
+
+## Why This Framework is Deprecated
+
+1. **Spring Cloud Connectors is in maintenance mode** (since July 2019)
+2. **No security updates or bug fixes** will be provided
+3. **Not compatible with modern Spring Boot** (3.x+)
+4. **Replaced by java-cfenv** - the official successor library
+
+## Migration Path
+
+| Your Application | Recommended Action |
+|------------------|-------------------|
+| **Spring Boot 3.x** | **Migrate to [java-cfenv](framework-java-cfenv.md) NOW** |
+| **Spring Boot 2.x** | Plan migration to java-cfenv when upgrading to Spring Boot 3.x |
+| **Legacy Spring apps** | Consider upgrading to Spring Boot 3.x + java-cfenv |
+
+**See**: [Complete Migration Guide](spring-auto-reconfiguration-migration.md)
+
+## Re-enabling (NOT RECOMMENDED)
+
+If you absolutely must re-enable this deprecated framework temporarily:
+
+```bash
+cf set-env my-app JBP_CONFIG_SPRING_AUTO_RECONFIGURATION '{enabled: true}'
+cf restage my-app
+```
+
+**⚠️ WARNING**: This is a temporary workaround only. Plan your migration immediately.
| Detection Criterion |
- Existence of a spring-core*.jar file in the application directory |
+ Existence of a spring-core*.jar file in the application directory AND explicitly enabled via configuration |
| Tags |
- spring-auto-reconfiguration=<version> |
+ spring-auto-reconfiguration=<version> (only when enabled) |
+
+
+ | Default |
+ DISABLED (as of Dec 2025) |
Tags are printed to standard output by the buildpack detect script
-If a `/WEB-INF/web.xml` file exists, the framework will modify it in addition to making the auto reconfiguration JAR available on the classpath. These modifications include:
-
-1. Augmenting `contextConfigLocation`. The function starts be enumerating the current `contextConfigLocation`s. If none exist, a default configuration is created with `/WEB-INF/application-context.xml` or `/WEB-INF/-servlet.xml` as the default. An additional location is then added to the collection of locations; `classpath:META- INF/cloud/cloudfoundry-auto-reconfiguration-context.xml` if the `ApplicationContext` is XML-based, `org.cloudfoundry.reconfiguration.spring.web.CloudAppAnnotationConfigAutoReconfig` if the `ApplicationContext` is annotation-based.
-1. Augmenting `contextInitializerClasses`. The function starts by enumerating the current `contextInitializerClasses`. If none exist, a default configuration is created with no value as the default. The `org.cloudfoundry.reconfiguration.spring.CloudApplicationContextInitializer` class is then added to the collection of classes.
+The Spring Auto-reconfiguration Framework adds the `cloud` profile to any existing Spring profiles such as those defined in the [`SPRING_PROFILES_ACTIVE`][] environment variable. It also uses the [Spring Cloud Cloud Foundry Connector][] to replace any bean of a candidate type with one mapped to a bound service instance. Please see the [Auto-Reconfiguration][] project for more details.
## Configuration
-For general information on configuring the buildpack, refer to [Configuration and Extension][].
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
-The framework can be configured by modifying the [`config/spring_auto_reconfiguration.yml`][] file. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+The framework can be configured by modifying the [`config/spring_auto_reconfiguration.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
| Name | Description
| ---- | -----------
-| `repository_root` | The URL of the Auto Reconfiguration repository index ([details][repositories]).
-| `version` | The version of Auto Reconfiguration to use. Candidate versions can be found in [this listing][].
+| `enabled` | Whether to attempt auto-reconfiguration. **Default: `false`** (disabled since Dec 2025)
+| `repository_root` | The URL of the Auto-reconfiguration repository index ([details][repositories]).
+| `version` | The version of Auto-reconfiguration to use. Candidate versions can be found in [this listing][].
+
+### Enabling Spring Auto-reconfiguration
+
+To enable this deprecated framework, set the environment variable:
+
+```bash
+cf set-env my-app JBP_CONFIG_SPRING_AUTO_RECONFIGURATION '{enabled: true}'
+cf restage my-app
+```
+
+**Warning**: You will see deprecation warnings in your logs when this framework is enabled.
+[Auto-Reconfiguration]: https://github.com/cloudfoundry/java-buildpack-auto-reconfiguration
[Configuration and Extension]: ../README.md#configuration-and-extension
[`config/spring_auto_reconfiguration.yml`]: ../config/spring_auto_reconfiguration.yml
[repositories]: extending-repositories.md
+[Spring Cloud Cloud Foundry Connector]: https://cloud.spring.io/spring-cloud-connectors/spring-cloud-cloud-foundry-connector.html
[this listing]: http://download.pivotal.io.s3.amazonaws.com/auto-reconfiguration/index.yml
[version syntax]: extending-repositories.md#version-syntax-and-ordering
+[`SPRING_PROFILES_ACTIVE`]: http://docs.spring.io/spring/docs/4.0.0.RELEASE/javadoc-api/org/springframework/core/env/AbstractEnvironment.html#ACTIVE_PROFILES_PROPERTY_NAME
diff --git a/docs/framework-spring_insight.md b/docs/framework-spring_insight.md
index 602c601ccb..b6ca64c5fa 100644
--- a/docs/framework-spring_insight.md
+++ b/docs/framework-spring_insight.md
@@ -1,12 +1,15 @@
# Spring Insight Framework
-The Spring Insight Framework causes an application to be automatically configured to work with a bound [Spring Insight Service][].
+
+> **DEPRECATED**: Spring Insight is an obsolete monitoring tool that has been replaced by modern APM solutions (New Relic, AppDynamics, Dynatrace, etc.). This framework is no longer actively maintained and is not recommended for new deployments.
+
+The Spring Insight Framework causes an application to be automatically configured to work with a bound [Spring Insight Service][]. This feature will only work with Spring Insight versions of 2.0.0.x or above.
| Detection Criterion |
Existence of a single bound Spring Insight service.
- - Existence of a Spring Insight service is defined as the
VCAP_SERVICES payload containing a service who's name, label or tag has insight as a substring.
+ - Existence of a Spring Insight service is defined as the
VCAP_SERVICES payload containing a service who's name, label or tag has insight as a substring.
|
diff --git a/docs/framework-your_kit_profiler.md b/docs/framework-your_kit_profiler.md
new file mode 100644
index 0000000000..8c56095116
--- /dev/null
+++ b/docs/framework-your_kit_profiler.md
@@ -0,0 +1,46 @@
+# YourKit Profiler Framework
+The YourKit Profiler Framework contributes YourKit Profiler configuration to the application at runtime.
+
+
+
+ | Detection Criterion |
+ enabled set in the config/your_kit_profiler.yml file |
+
+
+ | Tags |
+ your-kit-profiler=<version> |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The framework can be configured by creating or modifying the [`config/your_kit_profiler.yml`][] file in the buildpack fork. The framework uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+| Name | Description
+| ---- | -----------
+| `default_session_name` | The session name to display in the YourKit Profiler UI. Defaults to `:`.
+| `enabled` | Whether to enable the YourKit Profiler
+| `port` | The port that the YourKit Profiler will listen on. Defaults to `10001`.
+| `repository_root` | The URL of the YourKit Profiler repository index ([details][repositories]).
+| `version` | The version of the YourKit Profiler to use. Candidate versions can be found in the listings for [jammy][].
+
+## Creating SSH Tunnel
+After starting an application with the YourKit Profiler enabled, an SSH tunnel must be created to the container. To create that SSH container, execute the following command:
+
+```bash
+$ cf ssh -N -T -L :localhost:
+```
+
+The `REMOTE_PORT` should match the `port` configuration for the application (`10001` by default). The `LOCAL_PORT` can be any open port on your computer, but typically matches the `REMOTE_PORT` where possible.
+
+Once the SSH tunnel has been created, your YourKit Profiler should connect to `localhost:` for debugging.
+
+
+
+[`config/your_kit_profiler.yml`]: ../config/your_kit_profiler.yml
+[jammy]: https://download.run.pivotal.io/your-kit/bioni/x86_64/index.yml
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[repositories]: extending-repositories.md
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
diff --git a/docs/framework-your_kit_profiler.png b/docs/framework-your_kit_profiler.png
new file mode 100644
index 0000000000..3a036436be
Binary files /dev/null and b/docs/framework-your_kit_profiler.png differ
diff --git a/docs/java_opts-ruby-migration.md b/docs/java_opts-ruby-migration.md
new file mode 100644
index 0000000000..3bb60baf8f
--- /dev/null
+++ b/docs/java_opts-ruby-migration.md
@@ -0,0 +1,87 @@
+# Migrating JAVA_OPTS escaping from the Ruby buildpack
+
+The Go rewrite of the Java buildpack changed how `JAVA_OPTS` is assembled and
+passed to the JVM. If you are migrating configs written for the Ruby buildpack,
+the escaping rules are different.
+
+---
+
+## What changed
+
+| Mechanism | Ruby buildpack | Go buildpack |
+|-----------|---------------|-------------|
+| Launch | `eval exec java $JAVA_OPTS ...` | `javaexec` (shell-free tokenizer) |
+| `$VAR` in opts | expanded by shell at eval | expanded by `profile.d` at container start |
+| `$(cmd)` in opts | **executed** by shell | **never executed** (security fix, #1301) |
+| `\` handling | eval consumed one level of backslashes | `javaexec` POSIX: `\\`→`\`, `\"` → `"` |
+| `*` glob | expanded against filesystem | literal |
+
+---
+
+## Escaping comparison
+
+### Dollar sign before a variable name
+
+Both buildpacks expand `$VAR` references at runtime. No escaping needed or supported.
+
+```bash
+# Works the same in both buildpacks
+cf set-env my-app JAVA_OPTS '-Dserver.port=$PORT'
+```
+
+To prevent expansion, `\$` works in both buildpacks: `\$VAR` delivers the
+literal text `$VAR` to the JVM without expanding it.
+
+### Backslash
+
+```bash
+# Ruby buildpack: \\\\ in the manifest/env → \\ after eval → \ to JVM
+# Go buildpack: \\ in the manifest/env → \ to JVM (POSIX tokenizer, one level)
+```
+
+| Want to deliver to JVM | Ruby buildpack (env) | Go buildpack (env) |
+|------------------------|----------------------|--------------------|
+| one `\` | `\\\\` | `\\` |
+| two `\\` | `\\\\\\\\` | `\\\\` |
+| literal `\$PORT` | `\\\\\$PORT` | not supported — `$PORT` expands |
+
+### Cron expressions and glob characters (`*`)
+
+```bash
+# Ruby buildpack: must be quoted carefully to survive eval and glob expansion
+# Go buildpack: write literally — * never globs, no eval
+cf set-env my-app JAVA_OPTS '-DcronExpr=0 */7 * * *'
+```
+
+### Command substitution
+
+```bash
+# Ruby buildpack: $(hostname) in JAVA_OPTS was EXECUTED and replaced with output
+# Go buildpack: $(hostname) reaches the JVM as the literal string $(hostname)
+# This is intentional — executing user-supplied commands is unsafe
+```
+
+---
+
+## Quick migration checklist
+
+1. **Remove extra backslashes.** Replace `\\\\` with `\\` — the old pattern
+ survived two shell parse layers (eval) which no longer exist.
+
+2. **`\$VAR` still works.** Keep any `\$VAR` escapes you have — they are
+ honoured and pass the literal `$VAR` text to the JVM in both buildpacks.
+
+3. **Cron / glob expressions.** Remove any protective quoting that was needed
+ to survive `eval` — write the expression directly.
+
+4. **Command substitutions.** If you relied on `$(cmd)` being executed in
+ `JAVA_OPTS` (e.g. `$(hostname)`, `$(cat /etc/myconfig)`), that no longer
+ works. Compute the value before the app starts and set it as a separate
+ environment variable, then reference it via `$MYVAR` in `JAVA_OPTS`.
+
+---
+
+## References
+
+- [Java Options Framework](framework-java_opts.md)
+- Issue [#1301](https://github.com/cloudfoundry/java-buildpack/issues/1301) — remove `eval` from start command
diff --git a/docs/jre-graal_vm_jre.md b/docs/jre-graal_vm_jre.md
new file mode 100644
index 0000000000..770d5dbede
--- /dev/null
+++ b/docs/jre-graal_vm_jre.md
@@ -0,0 +1,221 @@
+# GraalVM JRE
+
+The GraalVM JRE provides Java runtimes from the [GraalVM][] project. No versions of the JRE are available by default due to licensing considerations. You must add GraalVM entries to the buildpack's `manifest.yml` file.
+
+
+
+ | Detection Criterion |
+ Configured via JBP_CONFIG_GRAAL_VM_JRE environment variable.
+
+ - Existence of a Volume Service is defined as the
VCAP_SERVICES payload containing a service whose name, label or tag has heap-dump as a substring.
+
+ |
+
+
+ | Tags |
+ graalvm=〈version〉, open-jdk-like-memory-calculator=〈version〉, jvmkill=〈version〉 |
+
+
+Tags are printed to standard output by the buildpack detect script.
+
+## Setup Requirements
+
+To use GraalVM, you must:
+
+1. **Fork the buildpack** and add GraalVM entries to `manifest.yml`
+2. **Package and upload** your custom buildpack to Cloud Foundry
+3. **Configure your application** to use GraalVM
+
+For complete step-by-step instructions, see the [Custom JRE Usage Guide](custom-jre-usage.md).
+
+## Adding GraalVM to manifest.yml
+
+Add the following to your forked buildpack's `manifest.yml`:
+
+```yaml
+# Add to url_to_dependency_map section:
+url_to_dependency_map:
+ - match: graalvm-community-jdk-(\d+\.\d+\.\d+)_linux-x64_bin\.tar\.gz
+ name: graalvm
+ version: $1
+
+# Add to default_versions section:
+default_versions:
+ - name: graalvm
+ version: 21.x
+
+# Add to dependencies section:
+dependencies:
+ # GraalVM Community Edition 17
+ - name: graalvm
+ version: 17.0.9
+ uri: https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-17.0.9/graalvm-community-jdk-17.0.9_linux-x64_bin.tar.gz
+ sha256:
+ cf_stacks:
+ - cflinuxfs4
+
+ # GraalVM Community Edition 21
+ - name: graalvm
+ version: 21.0.5
+ uri: https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.5/graalvm-community-jdk-21.0.5_linux-x64_bin.tar.gz
+ sha256:
+ cf_stacks:
+ - cflinuxfs4
+
+ # GraalVM Community Edition 23
+ - name: graalvm
+ version: 23.0.1
+ uri: https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-23.0.1/graalvm-community-jdk-23.0.1_linux-x64_bin.tar.gz
+ sha256:
+ cf_stacks:
+ - cflinuxfs4
+```
+
+### Calculating SHA256
+
+```bash
+# Download the JDK
+curl -LO https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.5/graalvm-community-jdk-21.0.5_linux-x64_bin.tar.gz
+
+# Calculate SHA256
+sha256sum graalvm-community-jdk-21.0.5_linux-x64_bin.tar.gz
+```
+
+### GraalVM Download URLs
+
+GraalVM Community Edition downloads are available at:
+- **GitHub Releases**: [graalvm/graalvm-ce-builds](https://github.com/graalvm/graalvm-ce-builds/releases)
+- **GraalVM Website**: [graalvm.org/downloads](https://www.graalvm.org/downloads/)
+
+For Oracle GraalVM (commercial), see the [Oracle GraalVM Downloads](https://www.oracle.com/java/technologies/downloads/).
+
+## Configuration
+
+After adding GraalVM to your buildpack's manifest, configure your application:
+
+```bash
+# Push with your custom buildpack
+cf push my-app -b my-custom-java-buildpack
+
+# Select GraalVM
+cf set-env my-app JBP_CONFIG_GRAAL_VM_JRE '{jre: {version: 21.+}}'
+
+# Restage to apply
+cf restage my-app
+```
+
+Or in your application's `manifest.yml`:
+
+```yaml
+applications:
+ - name: my-app
+ buildpacks:
+ - my-custom-java-buildpack
+ env:
+ JBP_CONFIG_GRAAL_VM_JRE: '{jre: {version: 21.+}}'
+```
+
+## Configuration Options
+
+| Name | Description |
+| ---- | ----------- |
+| `JBP_CONFIG_GRAAL_VM_JRE` | Configuration for GraalVM JRE, including version selection (e.g., `'{jre: {version: 21.+}}'`). |
+
+### Custom CA Certificates
+
+**Recommended approach:** Use [Cloud Foundry Trusted System Certificates](https://docs.cloudfoundry.org/devguide/deploy-apps/trusted-system-certificates.html). Operators deploy trusted certificates that are automatically available in `/etc/cf-system-certificates` and `/etc/ssl/certs`.
+
+## GraalVM Native Image
+
+This buildpack provides the GraalVM JRE for running standard Java applications on GraalVM's optimizing JIT compiler. For native image compilation, consider using [Paketo Buildpacks](https://paketo.io/) which have native image support.
+
+## JVMKill Agent
+
+The `jvmkill` agent runs when an application experiences a resource exhaustion event. When this occurs, the agent prints a histogram of the largest types by total bytes:
+
+```plain
+Resource exhaustion event: the JVM was unable to allocate memory from the heap.
+ResourceExhausted! (1/0)
+| Instance Count | Total Bytes | Class Name |
+| 18273 | 313157136 | [B |
+| 47806 | 7648568 | [C |
+| 14635 | 1287880 | Ljava/lang/reflect/Method; |
+| 46590 | 1118160 | Ljava/lang/String; |
+| 8413 | 938504 | Ljava/lang/Class; |
+| 28573 | 914336 | Ljava/util/concurrent/ConcurrentHashMap$Node; |
+```
+
+It also prints a summary of JVM memory spaces:
+
+```plain
+Memory usage:
+ Heap memory: init 65011712, used 332392888, committed 351797248, max 351797248
+ Non-heap memory: init 2555904, used 63098592, committed 64815104, max 377790464
+Memory pool usage:
+ Code Cache: init 2555904, used 14702208, committed 15007744, max 251658240
+ PS Eden Space: init 16252928, used 84934656, committed 84934656, max 84934656
+ PS Survivor Space: init 2621440, used 0, committed 19398656, max 19398656
+ Compressed Class Space: init 0, used 5249512, committed 5505024, max 19214336
+ Metaspace: init 0, used 43150616, committed 44302336, max 106917888
+ PS Old Gen: init 43515904, used 247459792, committed 247463936, max 247463936
+```
+
+If a [Volume Service][] with the string `heap-dump` in its name or tag is bound to the application, terminal heap dumps will be written with the pattern `/-/-/--.hprof`
+
+## Memory
+
+The total available memory for the application's container is specified when an application is pushed. The Java buildpack uses this value to control the JRE's use of various regions of memory and logs the JRE memory settings when the application starts or restarts.
+
+Note: If the total available memory is scaled up or down, the Java buildpack will re-calculate the JRE memory settings the next time the application is started.
+
+### Total Memory
+
+The user can change the container's total memory available to influence the JRE memory settings. Unless the user specifies the heap size Java option (`-Xmx`), increasing or decreasing the total memory available results in the heap size setting increasing or decreasing by a corresponding amount.
+
+### Loaded Classes
+
+The amount of memory allocated to metaspace and compressed class space is calculated from an estimate of the number of classes that will be loaded. The default behavior is to estimate the number of loaded classes as a fraction of the number of class files in the application. To specify a specific number:
+
+```yaml
+class_count: 500
+```
+
+### Headroom
+
+A percentage of total memory to leave as headroom:
+
+```yaml
+headroom: 10
+```
+
+### Stack Threads
+
+The amount of memory for stacks is given as memory per thread with `-Xss`. To specify an explicit thread count:
+
+```yaml
+stack_threads: 500
+```
+
+Note: The default of 250 threads is optimized for Tomcat. For non-blocking servers like Netty, use a smaller value (typically 25).
+
+### Memory Calculation
+
+Memory calculation happens before every `start` of an application and is performed by the [Java Buildpack Memory Calculator][]. No need to `restage` after scaling memory—restarting recalculates the settings.
+
+The JRE memory settings are logged when the application starts:
+
+```
+JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -XX:MaxMetaspaceSize=99199K \
+ -XX:ReservedCodeCacheSize=240M -XX:CompressedClassSpaceSize=18134K -Xss1M -Xmx368042K
+```
+
+## See Also
+
+- [Custom JRE Usage Guide](custom-jre-usage.md) - Complete instructions for adding BYOL JREs
+- [OpenJDK JRE](jre-open_jdk_jre.md) - Default JRE (no configuration required)
+
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[Custom JRE Usage Guide]: custom-jre-usage.md
+[GraalVM]: https://www.graalvm.org/
+[Java Buildpack Memory Calculator]: https://github.com/cloudfoundry/java-buildpack-memory-calculator
+[Volume Service]: https://docs.cloudfoundry.org/devguide/services/using-vol-services.html
diff --git a/docs/jre-ibm_jre.md b/docs/jre-ibm_jre.md
new file mode 100644
index 0000000000..a9a728b337
--- /dev/null
+++ b/docs/jre-ibm_jre.md
@@ -0,0 +1,184 @@
+# IBM Semeru JRE
+
+The IBM Semeru JRE provides Java runtimes built on Eclipse OpenJ9 from IBM. This includes both IBM Semeru Runtime Open Edition (free) and IBM Semeru Runtime Certified Edition (commercial). No versions of the JRE are available by default. You must add IBM Semeru entries to the buildpack's `manifest.yml` file.
+
+
+
+ | Detection Criterion |
+ Configured via JBP_CONFIG_IBM_JRE environment variable.
+
+ - Existence of a Volume Service is defined as the
VCAP_SERVICES payload containing a service whose name, label or tag has heap-dump as a substring.
+
+ |
+
+
+ | Tags |
+ ibm=〈version〉, open-jdk-like-memory-calculator=〈version〉 |
+
+
+Tags are printed to standard output by the buildpack detect script.
+
+## Setup Requirements
+
+To use IBM Semeru JRE, you must:
+
+1. **Fork the buildpack** and add IBM Semeru entries to `manifest.yml`
+2. **Package and upload** your custom buildpack to Cloud Foundry
+3. **Configure your application** to use IBM Semeru
+
+For complete step-by-step instructions, see the [Custom JRE Usage Guide](custom-jre-usage.md).
+
+## Adding IBM Semeru to manifest.yml
+
+Add the following to your forked buildpack's `manifest.yml`:
+
+```yaml
+# Add to url_to_dependency_map section:
+url_to_dependency_map:
+ - match: ibm-semeru-open-jre_x64_linux_(\d+\.\d+\.\d+)
+ name: ibm
+ version: $1
+
+# Add to default_versions section:
+default_versions:
+ - name: ibm
+ version: 17.x
+
+# Add to dependencies section:
+dependencies:
+ # IBM Semeru Runtime Open Edition 11
+ - name: ibm
+ version: 11.0.25
+ uri: https://github.com/ibmruntimes/semeru11-binaries/releases/download/jdk-11.0.25%2B9_openj9-0.48.0/ibm-semeru-open-jre_x64_linux_11.0.25_9_openj9-0.48.0.tar.gz
+ sha256:
+ cf_stacks:
+ - cflinuxfs4
+
+ # IBM Semeru Runtime Open Edition 17
+ - name: ibm
+ version: 17.0.13
+ uri: https://github.com/ibmruntimes/semeru17-binaries/releases/download/jdk-17.0.13%2B11_openj9-0.48.0/ibm-semeru-open-jre_x64_linux_17.0.13_11_openj9-0.48.0.tar.gz
+ sha256:
+ cf_stacks:
+ - cflinuxfs4
+
+ # IBM Semeru Runtime Open Edition 21
+ - name: ibm
+ version: 21.0.5
+ uri: https://github.com/ibmruntimes/semeru21-binaries/releases/download/jdk-21.0.5%2B11_openj9-0.48.0/ibm-semeru-open-jre_x64_linux_21.0.5_11_openj9-0.48.0.tar.gz
+ sha256:
+ cf_stacks:
+ - cflinuxfs4
+```
+
+### Calculating SHA256
+
+```bash
+# Download the JRE
+curl -LO "https://github.com/ibmruntimes/semeru17-binaries/releases/download/jdk-17.0.13%2B11_openj9-0.48.0/ibm-semeru-open-jre_x64_linux_17.0.13_11_openj9-0.48.0.tar.gz"
+
+# Calculate SHA256
+sha256sum ibm-semeru-open-jre_x64_linux_17.0.13_11_openj9-0.48.0.tar.gz
+```
+
+### IBM Semeru Download URLs
+
+IBM Semeru Runtime Open Edition downloads are available at:
+- **Java 11**: [semeru11-binaries releases](https://github.com/ibmruntimes/semeru11-binaries/releases)
+- **Java 17**: [semeru17-binaries releases](https://github.com/ibmruntimes/semeru17-binaries/releases)
+- **Java 21**: [semeru21-binaries releases](https://github.com/ibmruntimes/semeru21-binaries/releases)
+- **IBM Developer**: [IBM Semeru Downloads](https://developer.ibm.com/languages/java/semeru-runtimes/downloads/)
+
+## Configuration
+
+After adding IBM Semeru to your buildpack's manifest, configure your application:
+
+```bash
+# Push with your custom buildpack
+cf push my-app -b my-custom-java-buildpack
+
+# Select IBM Semeru JRE
+cf set-env my-app JBP_CONFIG_IBM_JRE '{jre: {version: 17.+}}'
+
+# Restage to apply
+cf restage my-app
+```
+
+Or in your application's `manifest.yml`:
+
+```yaml
+applications:
+ - name: my-app
+ buildpacks:
+ - my-custom-java-buildpack
+ env:
+ JBP_CONFIG_IBM_JRE: '{jre: {version: 17.+}}'
+```
+
+## Configuration Options
+
+| Name | Description |
+| ---- | ----------- |
+| `JBP_CONFIG_IBM_JRE` | Configuration for IBM Semeru JRE, including version selection (e.g., `'{jre: {version: 17.+}}'`). |
+
+### TLS Options
+
+For IBM Semeru/OpenJ9, it is recommended to use the following TLS options:
+
+```bash
+cf set-env my-app JAVA_OPTS '-Dcom.ibm.jsse2.overrideDefaultTLS=true'
+```
+
+### Custom CA Certificates
+
+**Recommended approach:** Use [Cloud Foundry Trusted System Certificates](https://docs.cloudfoundry.org/devguide/deploy-apps/trusted-system-certificates.html). Operators deploy trusted certificates that are automatically available in `/etc/cf-system-certificates` and `/etc/ssl/certs`.
+
+## OpenJ9 Features
+
+IBM Semeru Runtime uses the Eclipse OpenJ9 JVM, which provides:
+
+- **Shared Class Cache**: Faster startup times through class data sharing
+- **Lower Memory Footprint**: Optimized for container environments
+- **Pause-less GC Options**: Metronome and Balanced GC policies
+
+For OpenJ9-specific tuning options, see the [OpenJ9 Documentation](https://eclipse.dev/openj9/docs/).
+
+## Memory
+
+The total available memory for the application's container is specified when an application is pushed. The Java buildpack uses this value to control the JRE's use of various regions of memory and logs the JRE memory settings when the application starts or restarts.
+
+Note: If the total available memory is scaled up or down, the Java buildpack will re-calculate the JRE memory settings the next time the application is started.
+
+### Total Memory
+
+The user can change the container's total memory available to influence the JRE memory settings. Unless the user specifies the heap size Java option (`-Xmx`), increasing or decreasing the total memory available results in the heap size setting increasing or decreasing by a corresponding amount.
+
+### Memory Calculation
+
+The buildpack calculates the `-Xmx` memory setting based on the total memory available and the configured heap ratio.
+
+The container's total memory is logged during `cf push` and `cf scale`:
+
+```
+ state since cpu memory disk details
+#0 running 2017-04-10 02:20:03 PM 0.0% 896K of 1G 1.3M of 1G
+```
+
+## License
+
+IBM Semeru Runtime Open Edition is available under the [IBM International License Agreement for Non-Warranted Programs][].
+
+For IBM Semeru Runtime Certified Edition (commercial support), see [IBM product terms](https://www.ibm.com/terms).
+
+## See Also
+
+- [Custom JRE Usage Guide](custom-jre-usage.md) - Complete instructions for adding BYOL JREs
+- [OpenJDK JRE](jre-open_jdk_jre.md) - Default JRE (no configuration required)
+- [Eclipse OpenJ9 Documentation](https://eclipse.dev/openj9/docs/)
+- [IBM Knowledge Center][]
+
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[Custom JRE Usage Guide]: custom-jre-usage.md
+[IBM International License Agreement for Non-Warranted Programs]: http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?la_formnum=&li_formnum=L-PMAA-A3Z8P2&title=IBM%AE+SDK%2C+Java%99+Technology+Edition%2C+Version+8.0&l=en
+[IBM Knowledge Center]: http://www.ibm.com/support/knowledgecenter/SSYKE2/welcome_javasdk_family.html
+[Volume Service]: https://docs.cloudfoundry.org/devguide/services/using-vol-services.html
diff --git a/docs/jre-open_jdk_jre.md b/docs/jre-open_jdk_jre.md
index dff67f7296..4d290483de 100644
--- a/docs/jre-open_jdk_jre.md
+++ b/docs/jre-open_jdk_jre.md
@@ -1,83 +1,164 @@
# OpenJDK JRE
-The OpenJDK JRE provides Java runtimes from the [OpenJDK][] project. Versions of Java from the `1.6`, `1.7`, and `1.8` lines are available. Unless otherwise configured, the version of Java that will be used is specified in [`config/open_jdk_jre.yml`][].
+The OpenJDK JRE provides Java runtimes from the [OpenJDK][] project. Unless otherwise configured, the version of Java that will be used is specified in [`config/open_jdk_jre.yml`][].
| Detection Criterion |
- Unconditional |
+ Unconditional. Existence of a single bound Volume Service will result in Terminal heap dumps being written.
+
+ - Existence of a Volume Service service is defined as the
VCAP_SERVICES payload containing a service who's name, label or tag has heap-dump as a substring.
+
+ |
| Tags |
- open-jdk=〈version〉 |
+ open-jdk=〈version〉, open-jdk-like-memory-calculator=〈version〉, jvmkill=〈version〉 |
Tags are printed to standard output by the buildpack detect script
## Configuration
-For general information on configuring the buildpack, refer to [Configuration and Extension][].
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
-The JRE can be configured by modifying the [`config/open_jdk_jre.yml`][] file. The JRE uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+The JRE can be configured by modifying the [`config/open_jdk_jre.yml`][] file in the buildpack fork. The JRE uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
| Name | Description
| ---- | -----------
-| `repository_root` | The URL of the OpenJDK repository index ([details][repositories]).
-| `version` | The version of Java runtime to use. Candidate versions can be found in the listings for [centos6][], [lucid][], [mountainlion][], and [precise][]. Note: version 1.8.0 and higher require the `memory_sizes` and `memory_heuristics` mappings to specify `metaspace` rather than `permgen`.
-| `memory_sizes` | Optional memory sizes, described below under "Memory Sizes".
-| `memory_heuristics` | Default memory size weightings, described below under "Memory Weightings.
+| `jre.repository_root` | The URL of the OpenJDK repository index ([details][repositories]).
+| `jre.version` | The version of Java runtime to use. Candidate versions can be found in the listings for [jammy][]. Note: version 1.8.0 and higher require the `memory_sizes` and `memory_heuristics` mappings to specify `metaspace` rather than `permgen`.
+| `jvmkill.repository_root` | The URL of the `jvmkill` repository index ([details][repositories]).
+| `jvmkill.version` | The version of `jvmkill` to use. Candidate versions can be found in the listings for [jammy][jvmkill-jammy].
+| `memory_calculator` | Memory calculator defaults, described below under "Memory".
+
+### Additional Resources
+
+#### JCE Unlimited Strength
+**Note:** The `resources/open_jdk_jre` directory approach from the Ruby buildpack (2013-2025) is no longer supported. This was a **buildpack-level** feature where teams would fork the java-buildpack repository, add custom files to `resources/open_jdk_jre/`, and package their custom buildpack. The Go buildpack does not package the `resources/` directory.
+
+#### Custom CA Certificates
+**Note:** The `resources/` directory approach (Ruby buildpack, 2013-2025) is no longer supported. This was a **buildpack-level** feature for teams with forked buildpacks.
+
+**Recommended approach:** Use [Cloud Foundry Trusted System Certificates](https://docs.cloudfoundry.org/devguide/deploy-apps/trusted-system-certificates.html). Cloud Foundry operators can deploy trusted certificates that are automatically available to all apps in `/etc/cf-system-certificates` and `/etc/ssl/certs`. The JRE automatically trusts certificates in `/etc/ssl/certs`. This is the standard Cloud Foundry approach and works for all apps, not just Java apps.
+
+### `jvmkill`
+The `jvmkill` agent runs when an application has experience a resource exhaustion event. When this event occurs, the agent will print out a histogram of the first 100 largest types by total number of bytes.
+
+```plain
+Resource exhaustion event: the JVM was unable to allocate memory from the heap.
+ResourceExhausted! (1/0)
+| Instance Count | Total Bytes | Class Name |
+| 18273 | 313157136 | [B |
+| 47806 | 7648568 | [C |
+| 14635 | 1287880 | Ljava/lang/reflect/Method; |
+| 46590 | 1118160 | Ljava/lang/String; |
+| 8413 | 938504 | Ljava/lang/Class; |
+| 28573 | 914336 | Ljava/util/concurrent/ConcurrentHashMap$Node; |
+```
+
+It will also print out a summary of all of the memory spaces in the JVM.
+
+```plain
+Memory usage:
+ Heap memory: init 65011712, used 332392888, committed 351797248, max 351797248
+ Non-heap memory: init 2555904, used 63098592, committed 64815104, max 377790464
+Memory pool usage:
+ Code Cache: init 2555904, used 14702208, committed 15007744, max 251658240
+ PS Eden Space: init 16252928, used 84934656, committed 84934656, max 84934656
+ PS Survivor Space: init 2621440, used 0, committed 19398656, max 19398656
+ Compressed Class Space: init 0, used 5249512, committed 5505024, max 19214336
+ Metaspace: init 0, used 43150616, committed 44302336, max 106917888
+ PS Old Gen: init 43515904, used 247459792, committed 247463936, max 247463936
+```
+
+If a [Volume Service][] with the string `heap-dump` in its name or tag is bound to the application, terminal heap dumps will be written with the pattern `/-/-/--.hprof`
+
+```plain
+Heapdump written to /var/vcap/data/9ae0b817-1446-4915-9990-74c1bb26f147/pcfdev-space-e91c5c39/java-main-application-892f20ab/0-2017-06-13T18:31:29+0000-7b23124e.hprof
+```
### Memory
-The total available memory is specified when an application is pushed as part of it's configuration. The Java buildpack uses this value to control the JRE's use of various regions of memory. The JRE memory settings can be influenced by configuring the `memory_sizes` and/or `memory_heuristics` mappings.
+The total available memory for the application's container is specified when an application is pushed.
+The Java buildpack uses this value to control the JRE's use of various
+regions of memory and logs the JRE memory settings when the application starts or restarts.
+These settings can be influenced by configuring
+the `stack_threads` and/or `class_count` mappings (both part of the `memory_calculator` mapping),
+and/or Java options relating to memory.
-Note: if the total available memory is scaled up or down, the Java buildpack does not re-calculate the JRE memory settings until the next time the appication is pushed.
+Note: If the total available memory is scaled up or down, the Java buildpack will re-calculate the JRE memory settings the next time the application is started.
-#### Memory Sizes
-The following optional properties may be specified in the `memory_sizes` mapping.
+#### Total Memory
-| Name | Description
-| ---- | -----------
-| `heap` | The maximum heap size to use. It may be a single value such as `64m` or a range of acceptable values such as `128m..256m`. It is used to calculate the value of the Java command line options `-Xmx` and `-Xms`.
-| `metaspace` | The maximum Metaspace size to use. It is applicable to versions of OpenJDK from 1.8 onwards. It may be a single value such as `64m` or a range of acceptable values such as `128m..256m`. It is used to calculate the value of the Java command line options `-XX:MaxMetaspaceSize=` and `-XX:MetaspaceSize=`.
-| `permgen` | The maximum PermGen size to use. It is applicable to versions of OpenJDK earlier than 1.8. It may be a single value such as `64m` or a range of acceptable values such as `128m..256m`. It is used to calculate the value of the Java command line options `-XX:MaxPermSize=` and `-XX:PermSize=`.
-| `stack` | The stack size to use. It may be a single value such as `2m` or a range of acceptable values such as `2m..4m`. It is used to calculate the value of the Java command line option `-Xss`.
-| `native` | The amount of memory to reserve for native memory allocation. It should normally be omitted or specified as a range with no upper bound such as `100m..`. It does not correspond to a switch on the Java command line.
+The user can change the container's total memory available to influence the JRE memory settings.
+Unless the user specifies the heap size Java option (`-Xmx`), increasing or decreasing the total memory
+available results in the heap size setting increasing or decreasing by a corresponding amount.
-Memory sizes together with _memory weightings_ (described in the next section) are used to calculate the amount of memory for each memory type. The calculation is described later.
+#### Loaded Classes
-Memory sizes consist of a non-negative integer followed by a unit (`k` for kilobytes, `m` for megabytes, `g` for gigabytes; the case is not significant). Only the memory size `0` may be specified without a unit.
+The amount of memory that is allocated to metaspace and compressed class space (or, on Java 7, the permanent generation) is calculated from an estimate of the number of classes that will be loaded. The default behaviour is to estimate the number of loaded classes as a fraction of the number of class files in the application.
+If a specific number of loaded classes should be used for calculations, then it should be specified as in the following example:
-The above memory size properties may be omitted, specified as a single value, or specified as a range. Ranges use the syntax `..`, although either bound may be omitted in which case the defaults of zero and the total available memory are used for the lower bound and upper bound, respectively. Examples of ranges are `100m..200m` (any value between 100 and 200 megabytes, inclusive) and `100m..` (any value greater than or equal to 100 megabytes).
+```yaml
+class_count: 500
+```
-Each form of memory size is equivalent to a range. Omitting a memory size is equivalent to specifying the range `0..`. Specifying a single value is equivalent to specifying the range with that value as both the lower and upper bound, for example `128m` is equivalent to the range `128m..128m`.
+#### Headroom
-#### Memory Weightings
-Memory weightings are configured in the `memory_heuristics` mapping of [`config/open_jdk_jre.yml`][]. Each weighting is a non-negative number and represents a proportion of the total available memory (represented by the sum of all the weightings). For example, the following weightings:
+A percentage of the total memory allocated to the container to be left as headroom and excluded from the memory calculation.
```yaml
-memory_heuristics:
- heap: 15
- permgen: 5
- stack: 1
- native: 2
+headroom: 10
```
-represent a maximum heap size three times as large as the maximum PermGen size, and so on.
+#### Stack Threads
-Memory weightings are used together with memory ranges to calculate the amount of memory for each memory type, as follows.
+The amount of memory that should be allocated to stacks is given as an amount of memory per thread with the Java option `-Xss`. If an explicit number of threads should be used for the calculation of stack memory, then it should be specified as in the following example:
+
+```yaml
+stack_threads: 500
+```
+
+Note that the default value of 250 threads is optimized for a default Tomcat configuration. If you are using another container, especially something non-blocking like Netty, it's more appropriate to use a significantly smaller value. Typically 25 threads would cover the needs of both the server (Netty) and the threads started by the JVM itself.
+
+#### Java Options
+
+If the JRE memory settings need to be fine-tuned, the user can set one or more Java memory options to
+specific values. The heap size can be set explicitly, but changing the value of options other
+than the heap size can also affect the heap size. For example, if the user increases
+the maximum direct memory size from its default value of 10 Mb to 20 Mb, then this will
+reduce the calculated heap size by 10 Mb.
#### Memory Calculation
-The total available memory is allocated into heap, Metaspace or PermGen (depending on the version of OpenJDK), stack, and native memory types.
+Memory calculation happens before every `start` of an application and is performed by an external program, the [Java Buildpack Memory Calculator]. There is no need to `restage` an application after scaling the memory as restarting will cause the memory settings to be recalculated.
+
+The container's total available memory is allocated into heap, metaspace and compressed class space (or permanent generation for Java 7),
+direct memory, and stack memory settings.
+
+The memory calculation is described in more detail in the [Memory Calculator's README].
+
+The inputs to the memory calculation, except the container's total memory (which is unknown at staging time), are logged during staging, for example:
+```
+Loaded Classes: 13974, Threads: 300, JAVA_OPTS: ''
+```
-The total available memory is allocated to each memory type in proportion to its weighting. If the resultant size of a memory type lies outside its range, the size is constrained to
-the range, the constrained size is excluded from the remaining memory, and no further calculation is required for the memory type. If the resultant size of a memory size lies within its range, the size is included in the remaining memory. The remaining memory is then allocated to the remaining memory types in a similar fashion. Allocation terminates when none of the sizes of the remaining memory types is constrained by the corresponding range.
+The container's total memory is logged during `cf push` and `cf scale`, for example:
+```
+ state since cpu memory disk details
+#0 running 2017-04-10 02:20:03 PM 0.0% 896K of 1G 1.3M of 1G
+```
-Termination is guaranteed since there is a finite number of memory types and in each iteration either none of the remaining memory sizes is constrained by the corresponding range and allocation terminates or at least one memory size is constrained by the corresponding range and is omitted from the next iteration.
+The JRE memory settings are logged when the application is started or re-started, for example:
+```
+JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -XX:MaxMetaspaceSize=99199K \
+ -XX:ReservedCodeCacheSize=240M -XX:CompressedClassSpaceSize=18134K -Xss1M -Xmx368042K
+```
[`config/open_jdk_jre.yml`]: ../config/open_jdk_jre.yml
+[jammy]: https://java-buildpack.cloudfoundry.org/openjdk/jammy/x86_64/index.yml
[Configuration and Extension]: ../README.md#configuration-and-extension
-[centos6]: http://download.pivotal.io.s3.amazonaws.com/openjdk/centos6/x86_64/index.yml
-[lucid]: http://download.pivotal.io.s3.amazonaws.com/openjdk/lucid/x86_64/index.yml
-[mountainlion]: http://download.pivotal.io.s3.amazonaws.com/openjdk/mountainlion/x86_64/index.yml
+[Java Buildpack Memory Calculator]: https://github.com/cloudfoundry/java-buildpack-memory-calculator
+[jvmkill-jammy]: https://java-buildpack.cloudfoundry.org/jvmkill/jammy/x86_64/index.yml
+[Memory Calculator's README]: https://github.com/cloudfoundry/java-buildpack-memory-calculator
[OpenJDK]: http://openjdk.java.net
-[precise]: http://download.pivotal.io.s3.amazonaws.com/openjdk/precise/x86_64/index.yml
[repositories]: extending-repositories.md
[version syntax]: extending-repositories.md#version-syntax-and-ordering
+[Volume Service]: https://docs.cloudfoundry.org/devguide/services/using-vol-services.html
diff --git a/docs/jre-oracle_jre.md b/docs/jre-oracle_jre.md
index 8749925c75..34ef40ed03 100644
--- a/docs/jre-oracle_jre.md
+++ b/docs/jre-oracle_jre.md
@@ -1,90 +1,216 @@
# Oracle JRE
-The Oracle JRE provides Java runtimes from [Oracle][] project. No versions of the JRE are available be default due to licensing restrictions. Instead you will need to create a repository with the Oracle JREs in it and configure the buildpack to use that repository. Unless otherwise configured, the version of Java that will be used is specified in [`config/oracle_jre.yml`][].
+
+The Oracle JRE provides Java runtimes from [Oracle][]. No versions of the JRE are available by default due to licensing restrictions. You must add Oracle JRE entries to the buildpack's `manifest.yml` file.
| Detection Criterion |
- Unconditional |
+ Configured via JBP_CONFIG_ORACLE_JRE environment variable.
+
+ - Existence of a Volume Service service is defined as the
VCAP_SERVICES payload containing a service whose name, label or tag has heap-dump as a substring.
+
+ |
| Tags |
- oracle=〈version〉 |
+ oracle=〈version〉, open-jdk-like-memory-calculator=〈version〉, jvmkill=〈version〉 |
-Tags are printed to standard output by the buildpack detect script
+Tags are printed to standard output by the buildpack detect script.
+
+## Setup Requirements
+
+To use Oracle JRE, you must:
+
+1. **Fork the buildpack** and add Oracle JRE entries to `manifest.yml`
+2. **Package and upload** your custom buildpack to Cloud Foundry
+3. **Configure your application** to use the Oracle JRE
+
+For complete step-by-step instructions, see the [Custom JRE Usage Guide](custom-jre-usage.md).
+
+## Adding Oracle JRE to manifest.yml
+
+Add the following to your forked buildpack's `manifest.yml`:
+
+```yaml
+# Add to url_to_dependency_map section:
+url_to_dependency_map:
+ - match: jdk-(\d+\.\d+\.\d+)_linux-x64_bin\.tar\.gz
+ name: oracle
+ version: $1
+
+# Add to default_versions section:
+default_versions:
+ - name: oracle
+ version: 17.x
+
+# Add to dependencies section:
+dependencies:
+ # Oracle JDK 17
+ - name: oracle
+ version: 17.0.13
+ uri: https://download.oracle.com/java/17/archive/jdk-17.0.13_linux-x64_bin.tar.gz
+ sha256:
+ cf_stacks:
+ - cflinuxfs4
+
+ # Oracle JDK 21
+ - name: oracle
+ version: 21.0.5
+ uri: https://download.oracle.com/java/21/archive/jdk-21.0.5_linux-x64_bin.tar.gz
+ sha256:
+ cf_stacks:
+ - cflinuxfs4
+```
+
+### Calculating SHA256
+
+```bash
+# Download the JDK
+curl -LO https://download.oracle.com/java/17/archive/jdk-17.0.13_linux-x64_bin.tar.gz
-**NOTE:** Unlike the [OpenJDK JRE][], this JRE does not connect to a pre-populated repository. Instead you will need to create your own repository by:
+# Calculate SHA256
+sha256sum jdk-17.0.13_linux-x64_bin.tar.gz
+```
-1. Downloading the Oracle JRE binary (in TAR format) to an HTTP-accesible location
-1. Uploading an `index.yml` file with a mapping from the version of the JRE to its location to the same HTTP-accessible location
-1. Configuring the [`config/oracle_jre.yml`][] file to point to the root of the repository holding both the index and JRE binary
-1. Configuring the [`config/components.yml`][] file to disable the OpenJDK JRE and enable the Oracle JRE
+### Oracle Download URLs
-For details on the repository structure, see the [repository documentation][repositories].
+Oracle JDK downloads are available at:
+- **Java 17**: `https://download.oracle.com/java/17/archive/jdk-17.0.x_linux-x64_bin.tar.gz`
+- **Java 21**: `https://download.oracle.com/java/21/archive/jdk-21.0.x_linux-x64_bin.tar.gz`
+- **Latest versions**: [Oracle Java Downloads](https://www.oracle.com/java/technologies/downloads/)
## Configuration
-For general information on configuring the buildpack, refer to [Configuration and Extension][].
-The JRE can be configured by modifying the [`config/oracle_jre.yml`][] file. The JRE uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+After adding Oracle JRE to your buildpack's manifest, configure your application:
+
+```bash
+# Push with your custom buildpack
+cf push my-app -b my-custom-java-buildpack
+
+# Select Oracle JRE
+cf set-env my-app JBP_CONFIG_ORACLE_JRE '{jre: {version: 17.+}}'
+
+# Restage to apply
+cf restage my-app
+```
+
+Or in your application's `manifest.yml`:
-| Name | Description
-| ---- | -----------
-| `repository_root` | The URL of the Oracle repository index ([details][repositories]).
-| `version` | The version of Java runtime to use. Candidate versions can be found in the the repository that you have created to house the JREs. Note: version 1.8.0 and higher require the `memory_sizes` and `memory_heuristics` mappings to specify `metaspace` rather than `permgen`.
-| `memory_sizes` | Optional memory sizes, described below under "Memory Sizes".
-| `memory_heuristics` | Default memory size weightings, described below under "Memory Weightings.
+```yaml
+applications:
+ - name: my-app
+ buildpacks:
+ - my-custom-java-buildpack
+ env:
+ JBP_CONFIG_ORACLE_JRE: '{jre: {version: 17.+}}'
+```
+
+## Configuration Options
-### Memory
-The total available memory is specified when an application is pushed as part of it's configuration. The Java buildpack uses this value to control the JRE's use of various regions of memory. The JRE memory settings can be influenced by configuring the `memory_sizes` and/or `memory_heuristics` mappings.
+| Name | Description |
+| ---- | ----------- |
+| `JBP_CONFIG_ORACLE_JRE` | Configuration for Oracle JRE, including version selection (e.g., `'{jre: {version: 17.+}}'`). |
-Note: if the total available memory is scaled up or down, the Java buildpack does not re-calculate the JRE memory settings until the next time the appication is pushed.
+### Memory Configuration
-#### Memory Sizes
-The following optional properties may be specified in the `memory_sizes` mapping.
+Memory settings are configured via the memory calculator. See [Memory Configuration](#memory) below.
-| Name | Description
-| ---- | -----------
-| `heap` | The maximum heap size to use. It may be a single value such as `64m` or a range of acceptable values such as `128m..256m`. It is used to calculate the value of the Java command line options `-Xmx` and `-Xms`.
-| `metaspace` | The maximum Metaspace size to use. It is applicable to versions of Oracle from 1.8 onwards. It may be a single value such as `64m` or a range of acceptable values such as `128m..256m`. It is used to calculate the value of the Java command line options `-XX:MaxMetaspaceSize=` and `-XX:MetaspaceSize=`.
-| `permgen` | The maximum PermGen size to use. It is applicable to versions of Oracle earlier than 1.8. It may be a single value such as `64m` or a range of acceptable values such as `128m..256m`. It is used to calculate the value of the Java command line options `-XX:MaxPermSize=` and `-XX:PermSize=`.
-| `stack` | The stack size to use. It may be a single value such as `2m` or a range of acceptable values such as `2m..4m`. It is used to calculate the value of the Java command line option `-Xss`.
-| `native` | The amount of memory to reserve for native memory allocation. It should normally be omitted or specified as a range with no upper bound such as `100m..`. It does not correspond to a switch on the Java command line.
+### Custom CA Certificates
-Memory sizes together with _memory weightings_ (described in the next section) are used to calculate the amount of memory for each memory type. The calculation is described later.
+**Recommended approach:** Use [Cloud Foundry Trusted System Certificates](https://docs.cloudfoundry.org/devguide/deploy-apps/trusted-system-certificates.html). Operators deploy trusted certificates that are automatically available in `/etc/cf-system-certificates` and `/etc/ssl/certs`.
-Memory sizes consist of a non-negative integer followed by a unit (`k` for kilobytes, `m` for megabytes, `g` for gigabytes; the case is not significant). Only the memory size `0` may be specified without a unit.
+### JCE Unlimited Strength
-The above memory size properties may be omitted, specified as a single value, or specified as a range. Ranges use the syntax `..`, although either bound may be omitted in which case the defaults of zero and the total available memory are used for the lower bound and upper bound, respectively. Examples of ranges are `100m..200m` (any value between 100 and 200 megabytes, inclusive) and `100m..` (any value greater than or equal to 100 megabytes).
+Modern Oracle JDK versions (8u161+) include unlimited strength cryptography by default. No additional configuration is required.
-Each form of memory size is equivalent to a range. Omitting a memory size is equivalent to specifying the range `0..`. Specifying a single value is equivalent to specifying the range with that value as both the lower and upper bound, for example `128m` is equivalent to the range `128m..128m`.
+## JVMKill Agent
-#### Memory Weightings
-Memory weightings are configured in the `memory_heuristics` mapping of [`config/oracle_jre.yml`][]. Each weighting is a non-negative number and represents a proportion of the total available memory (represented by the sum of all the weightings). For example, the following weightings:
+The `jvmkill` agent runs when an application experiences a resource exhaustion event. When this occurs, the agent prints a histogram of the largest types by total bytes:
+
+```plain
+Resource exhaustion event: the JVM was unable to allocate memory from the heap.
+ResourceExhausted! (1/0)
+| Instance Count | Total Bytes | Class Name |
+| 18273 | 313157136 | [B |
+| 47806 | 7648568 | [C |
+| 14635 | 1287880 | Ljava/lang/reflect/Method; |
+| 46590 | 1118160 | Ljava/lang/String; |
+| 8413 | 938504 | Ljava/lang/Class; |
+| 28573 | 914336 | Ljava/util/concurrent/ConcurrentHashMap$Node; |
+```
+
+It also prints a summary of JVM memory spaces:
+
+```plain
+Memory usage:
+ Heap memory: init 65011712, used 332392888, committed 351797248, max 351797248
+ Non-heap memory: init 2555904, used 63098592, committed 64815104, max 377790464
+Memory pool usage:
+ Code Cache: init 2555904, used 14702208, committed 15007744, max 251658240
+ PS Eden Space: init 16252928, used 84934656, committed 84934656, max 84934656
+ PS Survivor Space: init 2621440, used 0, committed 19398656, max 19398656
+ Compressed Class Space: init 0, used 5249512, committed 5505024, max 19214336
+ Metaspace: init 0, used 43150616, committed 44302336, max 106917888
+ PS Old Gen: init 43515904, used 247459792, committed 247463936, max 247463936
+```
+
+If a [Volume Service][] with the string `heap-dump` in its name or tag is bound to the application, terminal heap dumps will be written with the pattern `/-/-/--.hprof`
+
+## Memory
+
+The total available memory for the application's container is specified when an application is pushed. The Java buildpack uses this value to control the JRE's use of various regions of memory and logs the JRE memory settings when the application starts or restarts.
+
+Note: If the total available memory is scaled up or down, the Java buildpack will re-calculate the JRE memory settings the next time the application is started.
+
+### Total Memory
+
+The user can change the container's total memory available to influence the JRE memory settings. Unless the user specifies the heap size Java option (`-Xmx`), increasing or decreasing the total memory available results in the heap size setting increasing or decreasing by a corresponding amount.
+
+### Loaded Classes
+
+The amount of memory allocated to metaspace and compressed class space is calculated from an estimate of the number of classes that will be loaded. The default behavior is to estimate the number of loaded classes as a fraction of the number of class files in the application. To specify a specific number:
```yaml
-memory_heuristics:
- heap: 15
- permgen: 5
- stack: 1
- native: 2
+class_count: 500
```
-represent a maximum heap size three times as large as the maximum PermGen size, and so on.
+### Headroom
-Memory weightings are used together with memory ranges to calculate the amount of memory for each memory type, as follows.
+A percentage of total memory to leave as headroom:
+
+```yaml
+headroom: 10
+```
-#### Memory Calculation
-The total available memory is allocated into heap, Metaspace or PermGen (depending on the version of Oracle), stack, and native memory types.
+### Stack Threads
+
+The amount of memory for stacks is given as memory per thread with `-Xss`. To specify an explicit thread count:
+
+```yaml
+stack_threads: 500
+```
+
+Note: The default of 250 threads is optimized for Tomcat. For non-blocking servers like Netty, use a smaller value (typically 25).
+
+### Memory Calculation
+
+Memory calculation happens before every `start` of an application and is performed by the [Java Buildpack Memory Calculator][]. No need to `restage` after scaling memory—restarting recalculates the settings.
+
+The JRE memory settings are logged when the application starts:
+
+```
+JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -XX:MaxMetaspaceSize=99199K \
+ -XX:ReservedCodeCacheSize=240M -XX:CompressedClassSpaceSize=18134K -Xss1M -Xmx368042K
+```
-The total available memory is allocated to each memory type in proportion to its weighting. If the resultant size of a memory type lies outside its range, the size is constrained to
-the range, the constrained size is excluded from the remaining memory, and no further calculation is required for the memory type. If the resultant size of a memory size lies within its range, the size is included in the remaining memory. The remaining memory is then allocated to the remaining memory types in a similar fashion. Allocation terminates when none of the sizes of the remaining memory types is constrained by the corresponding range.
+## See Also
-Termination is guaranteed since there is a finite number of memory types and in each iteration either none of the remaining memory sizes is constrained by the corresponding range and allocation terminates or at least one memory size is constrained by the corresponding range and is omitted from the next iteration.
+- [Custom JRE Usage Guide](custom-jre-usage.md) - Complete instructions for adding BYOL JREs
+- [OpenJDK JRE](jre-open_jdk_jre.md) - Default JRE (no configuration required)
-[`config/components.yml`]: ../config/components.yml
-[`config/oracle_jre.yml`]: ../config/oracle_jre.yml
[Configuration and Extension]: ../README.md#configuration-and-extension
-[OpenJDK JRE]: jre-open_jdk.md
-[Oracle]: http://www.oracle.com/technetwork/java/index.html
-[repositories]: extending-repositories.md
-[version syntax]: extending-repositories.md#version-syntax-and-ordering
+[Custom JRE Usage Guide]: custom-jre-usage.md
+[Java Buildpack Memory Calculator]: https://github.com/cloudfoundry/java-buildpack-memory-calculator
+[Oracle]: https://www.oracle.com/java/
+[Volume Service]: https://docs.cloudfoundry.org/devguide/services/using-vol-services.html
diff --git a/docs/jre-sap_machine_jre.md b/docs/jre-sap_machine_jre.md
new file mode 100644
index 0000000000..437190a76e
--- /dev/null
+++ b/docs/jre-sap_machine_jre.md
@@ -0,0 +1,168 @@
+# SapMachine JRE
+The SapMachine JRE provides Java runtimes from the [SapMachine][] project. Versions of Java from the `10` line are available. Unless otherwise configured, the version of Java that will be used is specified in [`config/sap_machine_jre.yml`][].
+
+
+
+ | Detection Criterion |
+ Unconditional. Existence of a single bound Volume Service will result in Terminal heap dumps being written.
+
+ - Existence of a Volume Service service is defined as the
VCAP_SERVICES payload containing a service who's name, label or tag has heap-dump as a substring.
+
+ |
+
+
+ | Tags |
+ open-jdk-like-jre=〈version〉, open-jdk-like-memory-calculator=〈version〉, jvmkill=〈version〉 |
+
+
+Tags are printed to standard output by the buildpack detect script
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The JRE can be configured by modifying the [`config/sap_machine_jre.yml`][] file in the buildpack fork. The JRE uses the [`Repository` utility support][repositories] and so it supports the [version syntax][] defined there.
+
+To use SapMachine JRE instead of OpenJDK, set environment variable and restage:
+
+```bash
+cf set-env JBP_CONFIG_SAP_MACHINE_JRE '{jre: {version: 17.+}}'
+cf restage
+```
+
+| Name | Description
+| ---- | -----------
+| `jre.repository_root` | The URL of the SapMachine repository index ([details][repositories]).
+| `jre.version` | The version of Java runtime to use. Candidate versions can be found in the listings for [jammy][]. Note: version 1.8.0 and higher require the `memory_sizes` and `memory_heuristics` mappings to specify `metaspace` rather than `permgen`.
+| `jvmkill.repository_root` | The URL of the `jvmkill` repository index ([details][repositories]).
+| `jvmkill.version` | The version of `jvmkill` to use. Candidate versions can be found in the listings for [jammy][jvmkill-jammy].
+| `memory_calculator` | Memory calculator defaults, described below under "Memory".
+
+### Additional Resources
+
+**Note:** The `resources/sap_machine_jre` directory approach from the Ruby buildpack (2013-2025) is no longer supported. This was a **buildpack-level** feature for teams with forked buildpacks. The Go buildpack does not package the `resources/` directory.
+
+#### Custom CA Certificates
+
+**Recommended approach:** Use [Cloud Foundry Trusted System Certificates](https://docs.cloudfoundry.org/devguide/deploy-apps/trusted-system-certificates.html). This is the standard Cloud Foundry approach and works for all apps. Operators deploy trusted certificates that are automatically available in `/etc/cf-system-certificates` and `/etc/ssl/certs`.
+
+### `jvmkill`
+The `jvmkill` agent runs when an application has experience a resource exhaustion event. When this event occurs, the agent will print out a histogram of the first 100 largest types by total number of bytes.
+
+```plain
+Resource exhaustion event: the JVM was unable to allocate memory from the heap.
+ResourceExhausted! (1/0)
+| Instance Count | Total Bytes | Class Name |
+| 18273 | 313157136 | [B |
+| 47806 | 7648568 | [C |
+| 14635 | 1287880 | Ljava/lang/reflect/Method; |
+| 46590 | 1118160 | Ljava/lang/String; |
+| 8413 | 938504 | Ljava/lang/Class; |
+| 28573 | 914336 | Ljava/util/concurrent/ConcurrentHashMap$Node; |
+```
+
+It will also print out a summary of all of the memory spaces in the JVM.
+
+```plain
+Memory usage:
+ Heap memory: init 65011712, used 332392888, committed 351797248, max 351797248
+ Non-heap memory: init 2555904, used 63098592, committed 64815104, max 377790464
+Memory pool usage:
+ Code Cache: init 2555904, used 14702208, committed 15007744, max 251658240
+ PS Eden Space: init 16252928, used 84934656, committed 84934656, max 84934656
+ PS Survivor Space: init 2621440, used 0, committed 19398656, max 19398656
+ Compressed Class Space: init 0, used 5249512, committed 5505024, max 19214336
+ Metaspace: init 0, used 43150616, committed 44302336, max 106917888
+ PS Old Gen: init 43515904, used 247459792, committed 247463936, max 247463936
+```
+
+If a [Volume Service][] with the string `heap-dump` in its name or tag is bound to the application, terminal heap dumps will be written with the pattern `/-/-/--.hprof`
+
+```plain
+Heapdump written to /var/vcap/data/9ae0b817-1446-4915-9990-74c1bb26f147/pcfdev-space-e91c5c39/java-main-application-892f20ab/0-2017-06-13T18:31:29+0000-7b23124e.hprof
+```
+
+### Memory
+The total available memory for the application's container is specified when an application is pushed.
+The Java buildpack uses this value to control the JRE's use of various
+regions of memory and logs the JRE memory settings when the application starts or restarts.
+These settings can be influenced by configuring
+the `stack_threads` and/or `class_count` mappings (both part of the `memory_calculator` mapping),
+and/or Java options relating to memory.
+
+Note: If the total available memory is scaled up or down, the Java buildpack will re-calculate the JRE memory settings the next time the application is started.
+
+#### Total Memory
+
+The user can change the container's total memory available to influence the JRE memory settings.
+Unless the user specifies the heap size Java option (`-Xmx`), increasing or decreasing the total memory
+available results in the heap size setting increasing or decreasing by a corresponding amount.
+
+#### Loaded Classes
+
+The amount of memory that is allocated to metaspace and compressed class space (or, on Java 7, the permanent generation) is calculated from an estimate of the number of classes that will be loaded. The default behaviour is to estimate the number of loaded classes as a fraction of the number of class files in the application.
+If a specific number of loaded classes should be used for calculations, then it should be specified as in the following example:
+
+```yaml
+class_count: 500
+```
+
+#### Headroom
+
+A percentage of the total memory allocated to the container to be left as headroom and excluded from the memory calculation.
+
+```yaml
+headroom: 10
+```
+
+#### Stack Threads
+
+The amount of memory that should be allocated to stacks is given as an amount of memory per thread with the Java option `-Xss`. If an explicit number of threads should be used for the calculation of stack memory, then it should be specified as in the following example:
+
+```yaml
+stack_threads: 500
+```
+
+Note that the default value of 250 threads is optimized for a default Tomcat configuration. If you are using another container, especially something non-blocking like Netty, it's more appropriate to use a significantly smaller value. Typically 25 threads would cover the needs of both the server (Netty) and the threads started by the JVM itself.
+
+#### Java Options
+
+If the JRE memory settings need to be fine-tuned, the user can set one or more Java memory options to
+specific values. The heap size can be set explicitly, but changing the value of options other
+than the heap size can also affect the heap size. For example, if the user increases
+the maximum direct memory size from its default value of 10 Mb to 20 Mb, then this will
+reduce the calculated heap size by 10 Mb.
+
+#### Memory Calculation
+Memory calculation happens before every `start` of an application and is performed by an external program, the [Java Buildpack Memory Calculator]. There is no need to `restage` an application after scaling the memory as restarting will cause the memory settings to be recalculated.
+
+The container's total available memory is allocated into heap, metaspace and compressed class space, direct memory, and stack memory settings.
+
+The memory calculation is described in more detail in the [Memory Calculator's README].
+
+The inputs to the memory calculation, except the container's total memory (which is unknown at staging time), are logged during staging, for example:
+```
+Loaded Classes: 13974, Threads: 300, JAVA_OPTS: ''
+```
+
+The container's total memory is logged during `cf push` and `cf scale`, for example:
+```
+ state since cpu memory disk details
+#0 running 2017-04-10 02:20:03 PM 0.0% 896K of 1G 1.3M of 1G
+```
+
+The JRE memory settings are logged when the application is started or re-started, for example:
+```
+JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -XX:MaxMetaspaceSize=99199K \
+ -XX:ReservedCodeCacheSize=240M -XX:CompressedClassSpaceSize=18134K -Xss1M -Xmx368042K
+```
+
+[`config/sap_machine_jre.yml`]: ../config/sap_machine_jre.yml
+[jammy]: https://java-buildpack.cloudfoundry.org/openjdk/jammy/x86_64/index.yml
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[Java Buildpack Memory Calculator]: https://github.com/cloudfoundry/java-buildpack-memory-calculator
+[jvmkill-jammy]: https://java-buildpack.cloudfoundry.org/jvmkill/jammy/x86_64/index.yml
+[Memory Calculator's README]: https://github.com/cloudfoundry/java-buildpack-memory-calculator
+[repositories]: extending-repositories.md
+[SapMachine]: https://sapmachine.io
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
+[Volume Service]: https://docs.cloudfoundry.org/devguide/services/using-vol-services.html
diff --git a/docs/jre-zing_jre.md b/docs/jre-zing_jre.md
new file mode 100644
index 0000000000..527f364d3b
--- /dev/null
+++ b/docs/jre-zing_jre.md
@@ -0,0 +1,203 @@
+# Azul Platform Prime JRE
+
+Azul Platform Prime (formerly Zing) provides high-performance Java runtimes from [Azul][]. No versions of the JRE are available by default due to licensing restrictions. You must add Azul Platform Prime JRE entries to the buildpack's `manifest.yml` file.
+
+
+
+ | Detection Criterion |
+ Configured via JBP_CONFIG_ZING_JRE environment variable.
+
+ - Existence of a Volume Service service is defined as the
VCAP_SERVICES payload containing a service whose name, label or tag has heap-dump as a substring.
+
+ |
+
+
+ | Tags |
+ zing=〈version〉, open-jdk-like-memory-calculator=〈version〉 |
+
+
+Tags are printed to standard output by the buildpack detect script.
+
+## Setup Requirements
+
+To use Azul Platform Prime JRE, you must:
+
+1. **Fork the buildpack** and add Azul Platform Prime JRE entries to `manifest.yml`
+2. **Package and upload** your custom buildpack to Cloud Foundry
+3. **Configure your application** to use the Azul Platform Prime JRE
+
+For complete step-by-step instructions, see the [Custom JRE Usage Guide](custom-jre-usage.md).
+
+## Adding Azul Platform Prime JRE to manifest.yml
+
+Add the following to your forked buildpack's `manifest.yml`:
+
+```yaml
+# Add to url_to_dependency_map section:
+url_to_dependency_map:
+ - match: zing(\d+\.\d+\.\d+\.\d+)-\d+-ca-jdk(\d+\.\d+\.\d+)-linux_x64\.tar\.gz
+ name: zing
+ version: $2
+
+# Add to default_versions section:
+default_versions:
+ - name: zing
+ version: 21.x
+
+# Add to dependencies section:
+dependencies:
+ # Azul Platform Prime JDK 17
+ - name: zing
+ version: 17.0.13
+ uri: https://cdn.azul.com/zing-zvm/feature-preview/zing24.10.0.0-3-ca-jdk17.0.13-linux_x64.tar.gz
+ sha256:
+ cf_stacks:
+ - cflinuxfs4
+
+ # Azul Platform Prime JDK 21
+ - name: zing
+ version: 21.0.5
+ uri: https://cdn.azul.com/zing-zvm/feature-preview/zing24.10.0.0-3-ca-jdk21.0.5-linux_x64.tar.gz
+ sha256:
+ cf_stacks:
+ - cflinuxfs4
+```
+
+### Calculating SHA256
+
+```bash
+# Download the JDK
+curl -LO https://cdn.azul.com/zing-zvm/feature-preview/zing24.10.0.0-3-ca-jdk17.0.13-linux_x64.tar.gz
+
+# Calculate SHA256
+sha256sum zing24.10.0.0-3-ca-jdk17.0.13-linux_x64.tar.gz
+```
+
+### Azul Platform Prime Download URLs
+
+Azul Platform Prime downloads require an Azul account and license. Contact Azul for access:
+- **Azul Platform Prime Downloads**: [https://www.azul.com/downloads/prime/](https://www.azul.com/downloads/prime/)
+- **Contact Azul**: [https://www.azul.com/contact-us/](https://www.azul.com/contact-us/)
+
+The URL patterns typically follow:
+- `https://cdn.azul.com/zing-zvm/feature-preview/zing-ca-jdk-linux_x64.tar.gz`
+
+## Configuration
+
+After adding Azul Platform Prime JRE to your buildpack's manifest, configure your application:
+
+```bash
+# Push with your custom buildpack
+cf push my-app -b my-custom-java-buildpack
+
+# Select Azul Platform Prime JRE
+cf set-env my-app JBP_CONFIG_ZING_JRE '{jre: {version: 21.+}}'
+
+# Restage to apply
+cf restage my-app
+```
+
+Or in your application's `manifest.yml`:
+
+```yaml
+applications:
+ - name: my-app
+ buildpacks:
+ - my-custom-java-buildpack
+ env:
+ JBP_CONFIG_ZING_JRE: '{jre: {version: 21.+}}'
+```
+
+## Configuration Options
+
+| Name | Description |
+| ---- | ----------- |
+| `JBP_CONFIG_ZING_JRE` | Configuration for Azul Platform Prime JRE, including version selection (e.g., `'{jre: {version: 21.+}}'`). |
+
+### Memory Configuration
+
+Memory settings are configured via the memory calculator. See [Memory Configuration](#memory) below.
+
+### Custom CA Certificates
+
+**Recommended approach:** Use [Cloud Foundry Trusted System Certificates](https://docs.cloudfoundry.org/devguide/deploy-apps/trusted-system-certificates.html). Operators deploy trusted certificates that are automatically available in `/etc/cf-system-certificates` and `/etc/ssl/certs`.
+
+## JVMKill / Out of Memory Handling
+
+Azul Platform Prime JRE does not use the jvmkill agent. Instead, it uses the `-XX:ExitOnOutOfMemoryError` flag by default, which terminates the JVM process when an out-of-memory error occurs.
+
+If a [Volume Service][] with the string `heap-dump` in its name or tag is bound to the application, terminal heap dumps will be written with the pattern `/-/-/--.hprof`
+
+```plain
+Heapdump written to /var/vcap/data/9ae0b817-1446-4915-9990-74c1bb26f147/pcfdev-space-e91c5c39/java-main-application-892f20ab/0-2017-06-13T18:31:29+0000-7b23124e.hprof
+```
+
+## Memory
+
+The total available memory for the application's container is specified when an application is pushed. The Java buildpack uses this value to control the JRE's use of various regions of memory and logs the JRE memory settings when the application starts or restarts.
+
+Note: If the total available memory is scaled up or down, the Java buildpack will re-calculate the JRE memory settings the next time the application is started.
+
+### Total Memory
+
+The user can change the container's total memory available to influence the JRE memory settings. Unless the user specifies the heap size Java option (`-Xmx`), increasing or decreasing the total memory available results in the heap size setting increasing or decreasing by a corresponding amount.
+
+### Loaded Classes
+
+The amount of memory allocated to metaspace and compressed class space is calculated from an estimate of the number of classes that will be loaded. The default behavior is to estimate the number of loaded classes as a fraction of the number of class files in the application. To specify a specific number:
+
+```yaml
+class_count: 500
+```
+
+### Headroom
+
+A percentage of total memory to leave as headroom:
+
+```yaml
+headroom: 10
+```
+
+### Stack Threads
+
+The amount of memory for stacks is given as memory per thread with `-Xss`. To specify an explicit thread count:
+
+```yaml
+stack_threads: 500
+```
+
+Note: The default of 250 threads is optimized for Tomcat. For non-blocking servers like Netty, use a smaller value (typically 25).
+
+### Memory Calculation
+
+Memory calculation happens before every `start` of an application and is performed by the [Java Buildpack Memory Calculator][]. No need to `restage` after scaling memory—restarting recalculates the settings.
+
+The JRE memory settings are logged when the application starts:
+
+```
+JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -XX:MaxMetaspaceSize=99199K \
+ -XX:ReservedCodeCacheSize=240M -XX:CompressedClassSpaceSize=18134K -Xss1M -Xmx368042K
+```
+
+## Azul Platform Prime Features
+
+Azul Platform Prime includes advanced features beyond standard OpenJDK:
+
+- **ReadyNow!**: Eliminates JVM warm-up time through persistent compilation profiles
+- **Falcon JIT Compiler**: LLVM-based JIT compiler for better peak performance
+- **C4 Garbage Collector**: Pauseless garbage collection for low-latency applications
+- **Optimizer Hub**: Cloud-based compilation optimization (requires separate configuration)
+
+Refer to [Azul Platform Prime documentation](https://docs.azul.com/prime/) for feature configuration.
+
+## See Also
+
+- [Custom JRE Usage Guide](custom-jre-usage.md) - Complete instructions for adding BYOL JREs
+- [OpenJDK JRE](jre-open_jdk_jre.md) - Default JRE (no configuration required)
+- [Azul Zulu JRE](jre-zulu_jre.md) - Azul's OpenJDK-based offering (included in manifest)
+
+[Azul]: https://www.azul.com/products/prime/
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[Custom JRE Usage Guide]: custom-jre-usage.md
+[Java Buildpack Memory Calculator]: https://github.com/cloudfoundry/java-buildpack-memory-calculator
+[Volume Service]: https://docs.cloudfoundry.org/devguide/services/using-vol-services.html
diff --git a/docs/jre-zulu_jre.md b/docs/jre-zulu_jre.md
new file mode 100644
index 0000000000..2d3f7b26f8
--- /dev/null
+++ b/docs/jre-zulu_jre.md
@@ -0,0 +1,178 @@
+# Azul Zulu JRE
+Azul Zulu JRE provides Java runtimes developed by Azul team. Unless otherwise configured, the version of Java that will be used is specified in [`config/zulu_jre.yml`][].
+
+
+
+ | Detection Criterion |
+ Unconditional. Existence of a single bound Volume Service will result in Terminal heap dumps being written.
+
+ - Existence of a Volume Service service is defined as the
VCAP_SERVICES payload containing a service who's name, label or tag has heap-dump as a substring.
+
+ |
+
+
+ | Tags |
+ open-jdk-like-jre=〈version〉, open-jdk-like-memory-calculator=〈version〉, jvmkill=〈version〉 |
+
+
+Tags are printed to standard output by the buildpack detect script.
+
+
+## Configuration
+For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].
+
+The JRE can be configured by modifying the [`config/zulu_jre.yml`][] file in the buildpack fork. The JRE uses the [`Repository` utility support][repositories] and so, it supports the [version syntax][] defined there.
+
+To use Zulu JRE instead of OpenJDK, set environment variable and restage:
+
+```bash
+cf set-env JBP_CONFIG_ZULU_JRE '{jre: {version: 17.+}}'
+cf restage
+```
+
+| Name | Description
+| ---- | -----------
+| `jre.repository_root` | The URL of the Zulu repository index ([details][repositories]).
+| `jre.version` | The version of Java runtime to use. Note: version 1.8.0 and higher require the `memory_sizes` and `memory_heuristics` mappings to specify `metaspace` rather than `permgen`.
+| `jvmkill.repository_root` | The URL of the `jvmkill` repository index ([details][repositories]).
+| `jvmkill.version` | The version of `jvmkill` to use. Candidate versions can be found in the listings for [jammy][jvmkill-jammy].
+| `memory_calculator` | Memory calculator defaults, described below under "Memory".
+
+### Additional Resources
+
+**Note:** The `resources/zulu_jre` directory approach from the Ruby buildpack (2013-2025) is no longer supported. This was a **buildpack-level** feature where teams would fork the java-buildpack repository, add custom files to `resources/zulu_jre/`, and package their custom buildpack. The Go buildpack does not package the `resources/` directory.
+
+#### JCE Unlimited Strength
+To add custom JCE Unlimited Strength files, you must:
+1. Fork the buildpack repository
+2. Add your `local_policy.jar` to the appropriate location in your fork
+3. Modify `manifest.yml` to include your custom files in the buildpack package
+4. Package and install your custom buildpack to Cloud Foundry
+
+#### Custom CA Certificates
+
+**Recommended approach:** Use [Cloud Foundry Trusted System Certificates](https://docs.cloudfoundry.org/devguide/deploy-apps/trusted-system-certificates.html). Cloud Foundry operators can deploy trusted certificates that are automatically available to all apps in `/etc/cf-system-certificates` and `/etc/ssl/certs`. The JRE automatically trusts certificates in `/etc/ssl/certs`. **This is the standard Cloud Foundry approach and works for all apps.**
+
+### `jvmkill`
+The `jvmkill` agent runs when an application has experience a resource exhaustion event. When this event occurs, the agent will print out a histogram of the first 100 largest types by total number of bytes.
+
+```plain
+Resource exhaustion event: the JVM was unable to allocate memory from the heap.
+ResourceExhausted! (1/0)
+| Instance Count | Total Bytes | Class Name |
+| 18273 | 313157136 | [B |
+| 47806 | 7648568 | [C |
+| 14635 | 1287880 | Ljava/lang/reflect/Method; |
+| 46590 | 1118160 | Ljava/lang/String; |
+| 8413 | 938504 | Ljava/lang/Class; |
+| 28573 | 914336 | Ljava/util/concurrent/ConcurrentHashMap$Node; |
+```
+
+It will also print out a summary of all of the memory spaces in the JVM.
+
+```plain
+Memory usage:
+ Heap memory: init 65011712, used 332392888, committed 351797248, max 351797248
+ Non-heap memory: init 2555904, used 63098592, committed 64815104, max 377790464
+Memory pool usage:
+ Code Cache: init 2555904, used 14702208, committed 15007744, max 251658240
+ PS Eden Space: init 16252928, used 84934656, committed 84934656, max 84934656
+ PS Survivor Space: init 2621440, used 0, committed 19398656, max 19398656
+ Compressed Class Space: init 0, used 5249512, committed 5505024, max 19214336
+ Metaspace: init 0, used 43150616, committed 44302336, max 106917888
+ PS Old Gen: init 43515904, used 247459792, committed 247463936, max 247463936
+```
+
+If a [Volume Service][] with the string `heap-dump` in its name or tag is bound to the application, terminal heap dumps will be written with the pattern `/-/-/--.hprof`
+
+```plain
+Heapdump written to /var/vcap/data/9ae0b817-1446-4915-9990-74c1bb26f147/pcfdev-space-e91c5c39/java-main-application-892f20ab/0-2017-06-13T18:31:29+0000-7b23124e.hprof
+```
+
+### Memory
+The total available memory for the application's container is specified when an application is pushed.
+The Java buildpack uses this value to control the JRE's use of various
+regions of memory and logs the JRE memory settings when the application starts or restarts.
+These settings can be influenced by configuring
+the `stack_threads` and/or `class_count` mappings (both part of the `memory_calculator` mapping),
+and/or Java options relating to memory.
+
+Note: If the total available memory is scaled up or down, the Java buildpack will re-calculate the JRE memory settings the next time the application is started.
+
+#### Total Memory
+
+The user can change the container's total memory available to influence the JRE memory settings.
+Unless the user specifies the heap size Java option (`-Xmx`), increasing or decreasing the total memory
+available results in the heap size setting increasing or decreasing by a corresponding amount.
+
+#### Loaded Classes
+
+The amount of memory that is allocated to metaspace and compressed class space (or, on Java 7, the permanent generation) is calculated from an estimate of the number of classes that will be loaded. The default behaviour is to estimate the number of loaded classes as a fraction of the number of class files in the application.
+If a specific number of loaded classes should be used for calculations, then it should be specified as in the following example:
+
+```yaml
+class_count: 500
+```
+
+#### Headroom
+
+A percentage of the total memory allocated to the container to be left as headroom and excluded from the memory calculation.
+
+```yaml
+headroom: 10
+```
+
+#### Stack Threads
+
+The amount of memory that should be allocated to stacks is given as an amount of memory per thread with the Java option `-Xss`. If an explicit number of threads should be used for the calculation of stack memory, then it should be specified as in the following example:
+
+```yaml
+stack_threads: 500
+```
+
+Note that the default value of 250 threads is optimized for a default Tomcat configuration. If you are using another container, especially something non-blocking like Netty, it's more appropriate to use a significantly smaller value. Typically 25 threads would cover the needs of both the server (Netty) and the threads started by the JVM itself.
+
+#### Java Options
+
+If the JRE memory settings need to be fine-tuned, the user can set one or more Java memory options to
+specific values. The heap size can be set explicitly, but changing the value of options other
+than the heap size can also affect the heap size. For example, if the user increases
+the maximum direct memory size from its default value of 10 Mb to 20 Mb, then this will
+reduce the calculated heap size by 10 Mb.
+
+#### Memory Calculation
+Memory calculation happens before every `start` of an application and is performed by an external program, the [Java Buildpack Memory Calculator]. There is no need to `restage` an application after scaling the memory as restarting will cause the memory settings to be recalculated.
+
+The container's total available memory is allocated into heap, metaspace and compressed class space (or permanent generation for Java 7),
+direct memory, and stack memory settings.
+
+The memory calculation is described in more detail in the [Memory Calculator's README].
+
+The inputs to the memory calculation, except the container's total memory (which is unknown at staging time), are logged during staging, for example:
+```
+Loaded Classes: 13974, Threads: 300, JAVA_OPTS: ''
+```
+
+The container's total memory is logged during `cf push` and `cf scale`, for example:
+```
+ state since cpu memory disk details
+#0 running 2017-04-10 02:20:03 PM 0.0% 896K of 1G 1.3M of 1G
+```
+
+The JRE memory settings are logged when the application is started or re-started, for example:
+```
+JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -XX:MaxMetaspaceSize=99199K \
+ -XX:ReservedCodeCacheSize=240M -XX:CompressedClassSpaceSize=18134K -Xss1M -Xmx368042K
+```
+
+[`config/components.yml`]: ../config/components.yml
+[`config/zulu_jre.yml`]: ../config/zulu_jre.yml
+[Azul Zulu]: https://www.azul.com/products/zulu/
+[Configuration and Extension]: ../README.md#configuration-and-extension
+[Java Buildpack Memory Calculator]: https://github.com/cloudfoundry/java-buildpack-memory-calculator
+[jvmkill-jammy]: https://java-buildpack.cloudfoundry.org/jvmkill/jammy/x86_64/index.yml
+[Memory Calculator's README]: https://github.com/cloudfoundry/java-buildpack-memory-calculator
+[repositories]: extending-repositories.md
+[version syntax]: extending-repositories.md#version-syntax-and-ordering
+[Volume Service]: https://docs.cloudfoundry.org/devguide/services/using-vol-services.html
+[Zulu JRE]: jre-zulu_jre.md
diff --git a/docs/selective-dependency-packaging.md b/docs/selective-dependency-packaging.md
new file mode 100644
index 0000000000..154b1b4d37
--- /dev/null
+++ b/docs/selective-dependency-packaging.md
@@ -0,0 +1,886 @@
+# Selective Dependency Packaging
+
+**Status**: Proposed
+**Date**: 2026-04-01
+**Affects**: `libbuildpack/packager`, all CF buildpacks
+
+---
+
+## Table of Contents
+
+1. [Problem Statement](#1-problem-statement)
+2. [Goals and Non-Goals](#2-goals-and-non-goals)
+3. [Current Architecture](#3-current-architecture)
+4. [Proposed Architecture](#4-proposed-architecture)
+5. [Design Decisions](#5-design-decisions)
+6. [manifest.yml Changes](#6-manifestyml-changes)
+7. [libbuildpack/packager Changes](#7-libbuildpackpackager-changes)
+8. [scripts/package.sh Changes](#8-scriptspackagesh-changes)
+9. [java-buildpack Adoption](#9-java-buildpack-adoption)
+10. [Implementation Plan](#10-implementation-plan)
+11. [Testing Strategy](#11-testing-strategy)
+12. [Rollout Strategy](#12-rollout-strategy)
+13. [Open Questions](#13-open-questions)
+
+---
+
+## 1. Problem Statement
+
+Running `scripts/package.sh --cached` produces an **offline buildpack** — a zip that contains every
+dependency declared in `manifest.yml`. For the java-buildpack this means 47 binaries are bundled,
+covering every JRE distribution, every APM agent, every profiler, and every JDBC driver, regardless
+of whether the target platform will ever use them.
+
+**Concrete consequences**:
+
+- The resulting zip is very large, making it slow to upload and store.
+- Air-gapped environments that only use, say, OpenJDK + Tomcat are forced to carry agents for
+ Datadog, New Relic, JRebel, YourKit, SkyWalking, and dozens of other tools they will never need.
+- Operators cannot tailor a buildpack to their security posture (e.g., excluding a commercial agent
+ they don't have a license for).
+
+**This is not a java-buildpack-only problem.** Eight of the thirteen CF buildpacks have ten or more
+dependencies (python: 23, ruby: 22, dotnet-core: 20, php: 16, go: 13, nginx: 12, nodejs: 11) and
+face the same trade-off when building cached/offline releases.
+
+---
+
+## 2. Goals and Non-Goals
+
+### Goals
+
+- Allow operators to build a cached buildpack that contains only a **named subset** of dependencies.
+- Support both **ad-hoc exclusion** (`--exclude dep-a,dep-b`) and **named profiles** (`--profile minimal`).
+- Profiles are declared inside `manifest.yml` of each buildpack — no global registry needed.
+- The feature lives in **`libbuildpack/packager`** so every buildpack inherits it automatically.
+- **Fully backward compatible**: buildpacks that do not use the new flags are completely unaffected.
+
+### Non-Goals
+
+- Runtime dependency filtering (what the running buildpack installs for an app) — this is purely a
+ *packaging-time* concern.
+- Changing how `buildpack-packager` handles stacks — that mechanism is orthogonal and unchanged.
+- Automatic profile selection based on platform configuration.
+- A centralised profile registry shared across buildpacks.
+
+---
+
+## 3. Current Architecture
+
+### 3.1 Packaging pipeline (today)
+
+```
+scripts/package.sh --cached
+ └─ buildpack-packager build
+ --version=
+ --cached=true
+ --stack=cflinuxfs4
+ └─ packager.Package(bpDir, cacheDir, version, stack, cached=true)
+ ├─ validates stack against manifest
+ ├─ runs pre_package script
+ ├─ for every dependency that matches the stack:
+ │ ├─ downloadDependency() ← downloads ALL deps
+ │ └─ SHA256 verify
+ └─ ZipFiles() → java_buildpack-cached-cflinuxfs4-v.zip
+```
+
+### 3.2 Dependency declaration in manifest.yml (today)
+
+```yaml
+dependencies:
+ - name: datadog-javaagent
+ version: 1.42.1
+ uri: https://repo1.maven.org/...
+ sha256: e703547f...
+ cf_stacks:
+ - cflinuxfs4
+```
+
+Each dependency entry has: `name`, `version`, `uri`, `sha256`, `cf_stacks`.
+There is no concept of optionality, grouping, or profiles.
+
+### 3.3 Shared scripts
+
+`scripts/package.sh` and `scripts/.util/tools.sh` are **byte-for-byte identical** across all 13
+buildpacks (differing only in the default `stack=` value). Any new flag added to `buildpack-packager`
+needs only a trivial one-line change in the shared script template to become available everywhere.
+
+---
+
+## 4. Proposed Architecture
+
+### 4.1 Overview
+
+Three complementary mechanisms are added, all optional:
+
+| Mechanism | Flag | Where defined | Use case |
+|---|---|---|---|
+| Ad-hoc exclusion | `--exclude dep-a,dep-b` | CLI only | One-off builds, CI overrides |
+| Named profiles | `--profile minimal` | `manifest.yml` | Reusable, versioned subsets |
+| Profile override | `--include dep-a` | CLI only | Restore specific deps excluded by a profile |
+
+All are purely *packaging-time* filters. At runtime the buildpack behaves identically — components
+that rely on a dependency that was excluded simply will not find it and will not activate (the same
+as they would in an uncached buildpack where the network is unavailable).
+
+### 4.2 End-to-end flow (proposed)
+
+```
+scripts/package.sh --cached --profile minimal
+ └─ buildpack-packager build
+ --version=
+ --cached=true
+ --stack=cflinuxfs4
+ --profile=minimal ← NEW
+ └─ packager.PackageWithOptions(bpDir, cacheDir, version, stack, cached=true,
+ PackageOptions{Profile:"minimal", Exclude:[], Include:[]})
+ ├─ resolveExclusions(manifest, profile="minimal", exclude=[], include=[])
+ │ └─ returns map[string]struct{} of dep names to skip
+ ├─ for every dependency that matches the stack AND is not excluded:
+ │ ├─ downloadDependency() ← only selected deps
+ │ └─ SHA256 verify
+ └─ ZipFiles() → java_buildpack-cached-cflinuxfs4-minimal-v.zip
+
+scripts/package.sh --cached --profile minimal --include jprofiler-profiler
+ └─ buildpack-packager build
+ --version=
+ --cached=true
+ --stack=cflinuxfs4
+ --profile=minimal
+ --include=jprofiler-profiler ← NEW
+ └─ packager.PackageWithOptions(...)
+ ├─ resolveExclusions(manifest, profile="minimal", exclude=[], include=["jprofiler-profiler"])
+ │ ├─ computes profile exclusions → removes jprofiler-profiler from excluded set
+ │ └─ returns map without jprofiler-profiler
+ ├─ for every dependency that matches the stack AND is not excluded:
+ │ ├─ downloadDependency() ← minimal deps + jprofiler-profiler
+ │ └─ SHA256 verify
+ └─ ZipFiles() → java_buildpack-cached-cflinuxfs4-minimal+custom-v.zip
+```
+
+### 4.3 Zip filename convention
+
+The output filename gains a profile or exclusion suffix so that different variants can coexist:
+
+| Invocation | Output filename |
+|---|---|
+| `--cached` | `java_buildpack-cached-cflinuxfs4-v1.2.3.zip` |
+| `--cached --profile minimal` | `java_buildpack-cached-cflinuxfs4-minimal-v1.2.3.zip` |
+| `--cached --exclude newrelic` | `java_buildpack-cached-cflinuxfs4-custom-v1.2.3.zip` |
+| `--cached --profile minimal --include jprofiler-profiler` | `java_buildpack-cached-cflinuxfs4-minimal+custom-v1.2.3.zip` |
+| `--cached --profile minimal --exclude groovy` | `java_buildpack-cached-cflinuxfs4-minimal+custom-v1.2.3.zip` |
+
+---
+
+## 5. Design Decisions
+
+### 5.1 Why profiles live in manifest.yml, not a separate file
+
+`manifest.yml` is already the single source of truth for dependency metadata. Keeping profiles there
+means:
+
+- Profile definitions are versioned alongside the dependencies they reference.
+- `buildpack-packager summary` can be extended to also list profiles.
+- No new file format needs to be discovered or parsed by tooling.
+
+### 5.2 Why `--exclude` takes dependency *names* not *indices*
+
+Names are stable across manifest updates. Indices change whenever a dependency is added or removed.
+Using names also makes CI scripts and documentation self-documenting.
+
+### 5.3 Why profiles use `exclude` lists rather than `include` lists
+
+The manifest already declares the full set of available dependencies. Exclusion lists are shorter
+and require less maintenance: when a new optional dependency is added to the manifest it is
+automatically part of all profiles unless explicitly excluded. An inclusion-based profile would
+require every profile to be updated each time a new core dependency is added.
+
+The `minimal` profile is the one exception that benefits most from this: it excludes the long tail
+of optional agents, and the "include everything" case is simply the absence of any profile.
+
+### 5.4 Why the feature belongs in libbuildpack, not per-buildpack scripts
+
+All buildpacks share the same `buildpack-packager` binary (installed via `go install ...@latest`).
+Adding the feature to the packager makes it available to every buildpack immediately, with only a
+trivial script change per buildpack to expose the new flags. The alternative — implementing YAML
+manipulation in each buildpack's `package.sh` — would be duplicated across 13 repos and harder to
+keep consistent.
+
+### 5.5 Mutual exclusion: --profile and --exclude can be combined
+
+`--profile minimal --exclude groovy` is valid. The profile's exclusion list is computed first, then
+the `--exclude` list is unioned with it. This allows operators to start from a profile and trim
+further for a specific deployment.
+
+### 5.6 --include overrides profile exclusions (CLI only)
+
+`--profile minimal --include jprofiler-profiler` is valid. The profile's exclusion list is computed
+first, then any names in `--include` are removed from that set — effectively restoring those
+dependencies into the build. This allows operators to start from a profile and selectively add back
+specific deps without defining a new profile.
+
+`--include` and `--exclude` can both be passed alongside `--profile`. Order of resolution:
+1. Profile's `exclude` list is applied.
+2. `--exclude` CLI additions are unioned in.
+3. `--include` CLI overrides are removed from the set.
+
+`--include` without `--profile` is a no-op (nothing was excluded to begin with) but is treated as a
+warning rather than a hard error, since it is not necessarily a mistake in a scripted environment.
+
+### 5.7 Unknown dependency names are errors
+
+If `--exclude datadog-javaagent` is passed but `datadog-javaagent` does not exist in the manifest,
+`buildpack-packager` exits non-zero. This catches typos early rather than silently producing a zip
+that happens to be missing something unexpected.
+
+Same rule applies to profiles: referencing an unknown profile name is a hard error.
+
+---
+
+## 6. manifest.yml Changes
+
+### 6.1 New top-level field: `packaging_profiles`
+
+```yaml
+# manifest.yml (excerpt — new section added near the top)
+
+packaging_profiles:
+ minimal:
+ description: "JDKs and core CF utilities only. No APM agents, profilers, or JDBC drivers."
+ exclude:
+ - datadog-javaagent
+ - elastic-apm-agent
+ - azure-application-insights
+ - skywalking-agent
+ - splunk-otel-javaagent
+ - google-stackdriver-profiler
+ - open-telemetry-javaagent
+ - contrast-security
+ - newrelic
+ - sealights-agent
+ - jacoco
+ - jrebel
+ - your-kit-profiler
+ - jprofiler-profiler
+ - java-memory-assistant
+ - java-memory-assistant-cleanup
+ - luna-security-provider
+ - postgresql-jdbc
+ - mariadb-jdbc
+
+ standard:
+ description: "Core + open-source APM/observability. No commercial profilers or security providers."
+ exclude:
+ - jrebel
+ - your-kit-profiler
+ - jprofiler-profiler
+ - contrast-security
+ - sealights-agent
+ - luna-security-provider
+ - java-memory-assistant
+ - java-memory-assistant-cleanup
+```
+
+No changes to the `dependencies:` entries themselves. Existing dependency declarations remain
+unchanged so that the full set is still packaged when no profile or exclude flag is given.
+
+### 6.2 YAML schema for packaging_profiles
+
+```
+packaging_profiles:
+ : # string, no spaces, used as CLI value
+ description: # human-readable, shown in --help / summary
+ exclude: # list of dependency names (must exist in manifest)
+ -
+ - ...
+```
+
+---
+
+## 7. libbuildpack/packager Changes
+
+### 7.1 models.go — new struct fields
+
+```go
+// PackagingProfile defines a named dependency exclusion set for use at packaging time.
+type PackagingProfile struct {
+ Description string `yaml:"description"`
+ Exclude []string `yaml:"exclude"`
+}
+
+// Manifest — add PackagingProfiles field
+type Manifest struct {
+ Language string `yaml:"language"`
+ Stack string `yaml:"stack"`
+ IncludeFiles []string `yaml:"include_files"`
+ PrePackage string `yaml:"pre_package"`
+ Dependencies Dependencies `yaml:"dependencies"`
+ Defaults []struct {
+ Name string `yaml:"name"`
+ Version string `yaml:"version"`
+ } `yaml:"default_versions"`
+ PackagingProfiles map[string]PackagingProfile `yaml:"packaging_profiles"` // NEW
+}
+```
+
+### 7.2 packager.go — exclusion resolution and filtering
+
+New unexported helper `resolveExclusions`:
+
+```go
+// resolveExclusions returns the set of dependency names that should be skipped
+// during packaging. Resolution order:
+// 1. Profile's exclude list (if a profile is named).
+// 2. Explicit --exclude names are unioned in.
+// 3. Explicit --include names are removed (overrides profile exclusions).
+//
+// An error is returned if the profile name is unknown or if any exclude/include
+// name does not exist in the manifest.
+func resolveExclusions(manifest Manifest, profile string, exclude []string, include []string) (map[string]struct{}, error) {
+ // 1. Start with profile exclusions
+ result := make(map[string]struct{})
+ if profile != "" {
+ p, ok := manifest.PackagingProfiles[profile]
+ if !ok {
+ return nil, fmt.Errorf("packaging profile %q not found in manifest", profile)
+ }
+ for _, name := range p.Exclude {
+ result[name] = struct{}{}
+ }
+ }
+
+ // 2. Union with explicitly excluded names
+ for _, name := range exclude {
+ result[name] = struct{}{}
+ }
+
+ // 3. Remove explicitly included names (overrides profile)
+ for _, name := range include {
+ delete(result, name)
+ }
+
+ // 4. Validate: every exclude/include name must exist in the manifest
+ depNames := make(map[string]struct{})
+ for _, d := range manifest.Dependencies {
+ depNames[d.Name] = struct{}{}
+ }
+ for _, name := range append(exclude, include...) {
+ if _, ok := depNames[name]; !ok {
+ return nil, fmt.Errorf("dependency %q not found in manifest", name)
+ }
+ }
+
+ return result, nil
+}
+```
+
+`PackageOptions` struct and updated `Package` / `PackageWithOptions` signatures:
+
+```go
+type PackageOptions struct {
+ Profile string
+ Exclude []string
+ Include []string // deps to restore after profile exclusions are applied
+}
+
+func PackageWithOptions(bpDir, cacheDir, version, stack string, cached bool, opts PackageOptions) (string, error)
+
+// Package delegates to PackageWithOptions with zero-value opts for backward compat
+func Package(bpDir, cacheDir, version, stack string, cached bool) (string, error) {
+ return PackageWithOptions(bpDir, cacheDir, version, stack, cached, PackageOptions{})
+}
+```
+
+Updated inner dependency loop (the only logic change inside `PackageWithOptions`):
+
+```go
+ // Resolve which deps to skip BEFORE the download loop
+ excluded, err := resolveExclusions(manifest, opts.Profile, opts.Exclude, opts.Include)
+ if err != nil {
+ return "", err
+ }
+
+ for idx, d := range manifest.Dependencies {
+ // Skip excluded dependencies entirely — they are not downloaded
+ // and are not written into the packaged manifest.yml
+ if _, skip := excluded[d.Name]; skip {
+ continue
+ }
+
+ for _, s := range d.Stacks {
+ if stack == "" || s == stack {
+ dependencyMap := deps[idx]
+ if cached {
+ if file, err := downloadDependency(d, cacheDir); err != nil {
+ return "", err
+ } else {
+ updateDependencyMap(dependencyMap, file)
+ files = append(files, file)
+ }
+ }
+ if stack != "" {
+ delete(dependencyMap.(map[interface{}]interface{}), "cf_stacks")
+ }
+ dependenciesForStack = append(dependenciesForStack, dependencyMap)
+ break
+ }
+ }
+ }
+```
+
+Filename suffix logic (appended after the existing `cachedPart` / `stackPart` computation):
+
+```go
+ profilePart := ""
+ if opts.Profile != "" {
+ profilePart = "-" + opts.Profile
+ if len(opts.Exclude) > 0 || len(opts.Include) > 0 {
+ profilePart += "+custom"
+ }
+ } else if len(opts.Exclude) > 0 || len(opts.Include) > 0 {
+ profilePart = "-custom"
+ }
+
+ fileName := fmt.Sprintf(
+ "%s_buildpack%s%s%s-v%s.zip",
+ manifest.Language, cachedPart, profilePart, stackPart, version,
+ )
+```
+
+### 7.3 buildpack-packager/main.go — new CLI flags
+
+```go
+type buildCmd struct {
+ cached bool
+ anyStack bool
+ version string
+ cacheDir string
+ stack string
+ profile string // NEW
+ exclude string // NEW: comma-separated, parsed before calling PackageWithOptions
+ include string // NEW: comma-separated, parsed before calling PackageWithOptions
+}
+
+func (b *buildCmd) SetFlags(f *flag.FlagSet) {
+ f.StringVar(&b.version, "version", "", "version to build as")
+ f.BoolVar(&b.cached, "cached", false, "include dependencies")
+ f.StringVar(&b.cacheDir, "cachedir", packager.CacheDir, "cache dir")
+ f.StringVar(&b.stack, "stack", "", "stack to package buildpack for")
+ f.BoolVar(&b.anyStack, "any-stack", false, "package buildpack for any stack")
+ f.StringVar(&b.profile, "profile", "", "packaging profile defined in manifest.yml") // NEW
+ f.StringVar(&b.exclude, "exclude", "", "comma-separated dependency names to exclude") // NEW
+ f.StringVar(&b.include, "include", "", "comma-separated dependency names to include, overriding profile exclusions") // NEW
+}
+
+func (b *buildCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
+ // ... existing validation ...
+
+ // Parse exclude and include lists
+ parseCSV := func(s string) []string {
+ var out []string
+ for _, name := range strings.Split(s, ",") {
+ name = strings.TrimSpace(name)
+ if name != "" {
+ out = append(out, name)
+ }
+ }
+ return out
+ }
+
+ opts := packager.PackageOptions{
+ Profile: b.profile,
+ Exclude: parseCSV(b.exclude),
+ Include: parseCSV(b.include),
+ }
+
+ zipFile, err := packager.PackageWithOptions(".", b.cacheDir, b.version, b.stack, b.cached, opts)
+ // ... rest unchanged ...
+}
+```
+
+Updated `Usage()` string:
+
+```
+build -stack |-any-stack [-cached] [-version ]
+ [-cachedir ] [-profile ] [-exclude ]
+ [-include ]:
+
+ Creates a zip file from the current buildpack directory.
+
+ -profile Name of a packaging profile defined in manifest.yml's
+ packaging_profiles section. Profiles declare which dependencies
+ to exclude from the cached zip.
+
+ -exclude Comma-separated list of dependency names to exclude, in addition
+ to any exclusions implied by -profile. Names must exist in
+ manifest.yml. Example: -exclude datadog-javaagent,newrelic
+
+ -include Comma-separated list of dependency names to force-include,
+ overriding exclusions implied by -profile. Useful for starting
+ from a restrictive profile and adding back a single dep.
+ Example: -profile minimal -include jprofiler-profiler
+```
+
+### 7.4 summary.go — list available profiles
+
+The `buildpack-packager summary` subcommand should be extended to print available profiles when the
+manifest contains a `packaging_profiles` section:
+
+```
+Packaged binaries:
+...
+
+Default binary versions:
+...
+
+Packaging profiles:
+ minimal JDKs and core CF utilities only. No APM agents, profilers, or JDBC drivers.
+ standard Core + open-source APM/observability. No commercial profilers or security providers.
+```
+
+Implementation: iterate `manifest.PackagingProfiles` in sorted key order, print name + description.
+
+### 7.5 Backward compatibility
+
+The new `profile` and `exclude` parameters are added at the **end** of the `Package()` signature.
+All existing callers (other buildpack tests and tools that call `packager.Package` directly) must
+be updated to pass empty values:
+
+```go
+// Before
+packager.Package(bpDir, cacheDir, version, stack, cached)
+
+// After
+packager.Package(bpDir, cacheDir, version, stack, cached, "", nil)
+```
+
+Since `libbuildpack` is a Go module consumed via `go install ...@latest`, this is a breaking change
+to the Go API. Two options:
+
+**Option A — Update signature, update all callers in the same PR.**
+Clean, no shims. Requires coordinating one PR across `libbuildpack` and any internal tooling that
+calls `Package()` directly (currently only `buildpack-packager/main.go` and test files in
+`libbuildpack` itself).
+
+**Option B — Introduce a new function `PackageWithOptions`.**
+```go
+type PackageOptions struct {
+ Profile string
+ Exclude []string
+}
+
+func PackageWithOptions(bpDir, cacheDir, version, stack string, cached bool, opts PackageOptions) (string, error)
+
+// Package delegates to PackageWithOptions with zero-value opts for backward compat
+func Package(bpDir, cacheDir, version, stack string, cached bool) (string, error) {
+ return PackageWithOptions(bpDir, cacheDir, version, stack, cached, PackageOptions{})
+}
+```
+
+**Recommendation**: Option B. It keeps the existing `Package()` function intact and avoids a
+flag day across all consumers.
+
+---
+
+## 8. scripts/package.sh Changes
+
+Each buildpack's `scripts/package.sh` needs three additions:
+
+1. Parse `--profile`, `--exclude`, and `--include` in the `while` loop.
+2. Forward them to `buildpack-packager`.
+
+```bash
+function main() {
+ local stack version cached output profile exclude include
+ stack="cflinuxfs4"
+ cached="false"
+ output="${ROOTDIR}/build/buildpack.zip"
+ profile="" # NEW
+ exclude="" # NEW
+ include="" # NEW
+
+ while [[ "${#}" != 0 ]]; do
+ case "${1}" in
+ # ... existing cases unchanged ...
+
+ --profile) # NEW
+ profile="${2}"
+ shift 2
+ ;;
+
+ --exclude) # NEW
+ exclude="${2}"
+ shift 2
+ ;;
+
+ --include) # NEW
+ include="${2}"
+ shift 2
+ ;;
+
+ # ...
+ esac
+ done
+
+ package::buildpack "${version}" "${cached}" "${stack}" "${output}" "${profile}" "${exclude}" "${include}"
+}
+
+function package::buildpack() {
+ local version cached stack output profile exclude include
+ version="${1}"
+ cached="${2}"
+ stack="${3}"
+ output="${4}"
+ profile="${5}" # NEW
+ exclude="${6}" # NEW
+ include="${7}" # NEW
+
+ # ... existing setup ...
+
+ local profile_flag="" exclude_flag="" include_flag=""
+ [[ -n "${profile}" ]] && profile_flag="--profile=${profile}"
+ [[ -n "${exclude}" ]] && exclude_flag="--exclude=${exclude}"
+ [[ -n "${include}" ]] && include_flag="--include=${include}"
+
+ local file
+ file="$(
+ "${ROOTDIR}/.bin/buildpack-packager" build \
+ "--version=${version}" \
+ "--cached=${cached}" \
+ "${stack_flag}" \
+ ${profile_flag:+"${profile_flag}"} \
+ ${exclude_flag:+"${exclude_flag}"} \
+ ${include_flag:+"${include_flag}"} \
+ | xargs -n1 | grep -e '\.zip$'
+ )"
+
+ mv "${file}" "${output}"
+}
+```
+
+Updated `usage()`:
+
+```
+package.sh --version [OPTIONS]
+Packages the buildpack into a .zip file.
+OPTIONS
+ --help -h prints the command usage
+ --version specifies the version number
+ --cached bundle dependencies (default: false)
+ --stack target stack (default: cflinuxfs4)
+ --output output path (default: build/buildpack.zip)
+ --profile packaging profile from manifest.yml
+ --exclude additional dependencies to exclude
+ --include dependencies to restore, overriding profile exclusions
+```
+
+---
+
+## 9. java-buildpack Adoption
+
+### 9.1 manifest.yml profiles
+
+The following profiles are proposed for the java-buildpack. The dependency categorisation used
+here mirrors the analysis of the 47 dependencies in the current `manifest.yml`.
+
+**Core (never excluded by any profile)**:
+- JDKs: `openjdk`, `zulu`, `sapmachine` (all versions)
+- CF utilities: `jvmkill`, `memory-calculator`, `auto-reconfiguration`, `java-cfenv`,
+ `client-certificate-mapper`, `metric-writer`, `container-security-provider`,
+ `cf-metrics-exporter`
+- Tomcat family: `tomcat`, `tomcat-access-logging-support`, `tomcat-lifecycle-support`,
+ `tomcat-logging-support`
+- Other frameworks: `groovy`, `spring-boot-cli`
+
+**`minimal` profile** — excludes everything that requires a commercial license or serves a
+single vendor's ecosystem:
+```yaml
+ minimal:
+ description: "JDKs, CF utilities, Tomcat, and common frameworks only."
+ exclude:
+ - datadog-javaagent
+ - elastic-apm-agent
+ - azure-application-insights
+ - skywalking-agent
+ - splunk-otel-javaagent
+ - google-stackdriver-profiler
+ - open-telemetry-javaagent
+ - contrast-security
+ - newrelic
+ - sealights-agent
+ - jacoco
+ - jrebel
+ - your-kit-profiler
+ - jprofiler-profiler
+ - java-memory-assistant
+ - java-memory-assistant-cleanup
+ - luna-security-provider
+ - postgresql-jdbc
+ - mariadb-jdbc
+```
+Result: 47 → 28 dependencies bundled.
+
+**`standard` profile** — adds open-source observability (OTel, JaCoCo) and JDBC drivers, removes
+commercial profilers and specialist security providers:
+```yaml
+ standard:
+ description: "Core + open-source APM, OTel, and JDBC drivers. No commercial agents or profilers."
+ exclude:
+ - datadog-javaagent
+ - elastic-apm-agent
+ - azure-application-insights
+ - skywalking-agent
+ - splunk-otel-javaagent
+ - google-stackdriver-profiler
+ - contrast-security
+ - newrelic
+ - sealights-agent
+ - jrebel
+ - your-kit-profiler
+ - jprofiler-profiler
+ - java-memory-assistant
+ - java-memory-assistant-cleanup
+ - luna-security-provider
+```
+Result: 47 → 32 dependencies bundled.
+
+### 9.2 Typical usage examples
+
+```bash
+# Current behaviour — unchanged
+./scripts/package.sh --cached
+
+# Air-gapped environment, only OpenJDK + Tomcat needed
+./scripts/package.sh --cached --profile minimal
+
+# Standard ops team buildpack — OTel and JDBC included, commercial agents excluded
+./scripts/package.sh --cached --profile standard
+
+# Standard profile but also drop jacoco (not needed on this foundation)
+./scripts/package.sh --cached --profile standard --exclude jacoco
+
+# One-off: full cached buildpack minus the two agents we don't have licences for
+./scripts/package.sh --cached --exclude jrebel,your-kit-profiler,jprofiler-profiler
+
+# Standard profile, but this foundation also needs jprofiler for triage
+./scripts/package.sh --cached --profile standard --include jprofiler-profiler
+```
+
+---
+
+## 10. Implementation Plan
+
+The work is broken into three sequential phases. Phases 1 and 2 are in `libbuildpack`, Phase 3 is
+in `java-buildpack` (and optionally in other buildpacks).
+
+### Phase 1 — libbuildpack core (packager library)
+
+| # | File | Change | Notes |
+|---|---|---|---|
+| 1.1 | `packager/models.go` | Add `PackagingProfile` struct and `PackagingProfiles` field on `Manifest` | ~15 lines |
+| 1.2 | `packager/packager.go` | Add `resolveExclusions()` helper (profile + exclude + include logic) | ~40 lines |
+| 1.3 | `packager/packager.go` | Add `PackageOptions` struct, `PackageWithOptions`, update `Package` to delegate | ~20 lines |
+| 1.4 | `packager/packager.go` | Apply exclusion filter in dependency loop, update filename logic | ~15 lines |
+| 1.5 | `packager/summary.go` | Print `packaging_profiles` section in `Summary()` | ~20 lines |
+| 1.6 | `packager/packager_test.go` | Test cases for exclude, include, profile, combined, unknown name errors | ~100 lines |
+| 1.7 | `packager/models_test.go` | Test `resolveExclusions` edge cases | ~50 lines |
+
+**Entry criteria**: existing tests pass on `main`.
+**Exit criteria**: all new tests pass, `packager.Package()` signature unchanged, `PackageWithOptions` works.
+
+### Phase 2 — buildpack-packager CLI
+
+| # | File | Change | Notes |
+|---|---|---|---|
+| 2.1 | `packager/buildpack-packager/main.go` | Add `--profile`, `--exclude`, and `--include` flags to `buildCmd` | ~30 lines |
+| 2.2 | `packager/buildpack-packager/main.go` | Parse comma-separated `--exclude` and `--include` into `[]string` | ~15 lines |
+| 2.3 | `packager/buildpack-packager/main.go` | Update `Usage()` string | ~15 lines |
+
+**Exit criteria**: `buildpack-packager build --help` shows new flags; manual smoke test against
+java-buildpack `manifest.yml` produces expected zip sizes.
+
+### Phase 3 — java-buildpack adoption
+
+| # | File | Change | Notes |
+|---|---|---|---|
+| 3.1 | `manifest.yml` | Add `packaging_profiles` section with `minimal` and `standard` | ~40 lines |
+| 3.2 | `scripts/package.sh` | Add `--profile` / `--exclude` / `--include` flag parsing and forwarding | ~20 lines |
+| 3.3 | `scripts/package.sh` | Update `usage()` | ~5 lines |
+
+**Exit criteria**:
+- `./scripts/package.sh --cached --profile minimal` produces a zip with 28 dependencies.
+- `./scripts/package.sh --cached --profile minimal --include jprofiler-profiler` produces a zip with 29 dependencies.
+- `./scripts/package.sh --cached` produces a zip with 47 dependencies (unchanged).
+- `buildpack-packager summary` lists the two profiles.
+
+### Phase 4 (optional) — other buildpacks
+
+Any buildpack team can independently add a `packaging_profiles` section to their `manifest.yml`
+and the two-line script update to `scripts/package.sh`. No further changes to `libbuildpack` are
+required.
+
+---
+
+## 11. Testing Strategy
+
+### Unit tests (libbuildpack)
+
+| Scenario | Expected outcome |
+|---|---|
+| `PackageWithOptions` called with no profile, no exclude, no include | All stack-matching deps bundled (existing behaviour) |
+| `PackageWithOptions` called with `exclude=["dep-a"]` | `dep-a` absent from zip manifest and not downloaded |
+| `PackageWithOptions` called with valid `profile="minimal"` | Profile's exclude list applied correctly |
+| `PackageWithOptions` called with `profile` + extra `exclude` | Union of both exclude lists applied |
+| `PackageWithOptions` called with `profile` + `include` | Named dep restored; rest of profile exclusions still applied |
+| `PackageWithOptions` called with `profile` + `exclude` + `include` | exclude adds, include removes from profile exclusions |
+| `PackageWithOptions` called with `include` but no `profile` | No-op (nothing was excluded); warning emitted |
+| `PackageWithOptions` called with unknown `profile` name | Returns error containing profile name |
+| `PackageWithOptions` called with `exclude` containing unknown dep name | Returns error containing dep name |
+| `PackageWithOptions` called with `include` containing unknown dep name | Returns error containing dep name |
+| `Package` called (legacy signature) | Delegates to `PackageWithOptions` with zero opts; full behaviour unchanged |
+| Zip filename — profile only | Contains `-` segment, no `+custom` |
+| Zip filename — profile + include or exclude | Contains `-+custom` segment |
+| Zip filename — exclude only (no profile) | Contains `-custom` segment |
+| Zip filename — neither | Original filename (backward compat) |
+
+New fixture: `packager/fixtures/with_profiles/manifest.yml` — a minimal manifest with a
+`packaging_profiles` section used by the new tests.
+
+### Integration / smoke tests (java-buildpack CI)
+
+The existing `ci/package-test.sh` script can be extended to:
+
+1. Build `--profile minimal` and assert the zip does **not** contain `dependencies/*/dd-java-agent*`.
+2. Build `--cached` (no profile) and assert the zip **does** contain that file.
+3. Build `--exclude datadog-javaagent` and assert the same.
+
+These can run without downloading real binaries by mocking the packager's HTTP client (as the
+existing packager tests already do via `httpmock`).
+
+---
+
+## 12. Rollout Strategy
+
+1. **Land Phase 1+2 in `libbuildpack`** as a single PR. Tagging a new release is not strictly
+ required because all buildpacks use `@latest`, but a tag is recommended for traceability.
+
+2. **Land Phase 3 in `java-buildpack`** once the `libbuildpack` PR is merged and the binary
+ installed at `.bin/buildpack-packager` is refreshed in CI.
+
+3. **Communicate to other buildpack teams** that `--profile`, `--exclude`, and `--include` are now available.
+ Each team can adopt on their own schedule by adding `packaging_profiles` to their manifest.
+
+4. **No operator action required** for existing deployments. Operators who build the buildpack
+ without `--profile`, `--exclude`, or `--include` get identical output to today.
+
+---
+
+## 13. Open Questions
+
+| # | Question | Options | Decision |
+|---|---|---|---|
+| Q1 | Should `--exclude`/`--include` on an uncached buildpack be an error or a no-op? | Error vs no-op with warning | Recommend: **no-op with a warning** — the flags are meaningless for uncached builds but not necessarily a mistake |
+| Q2 | Should profile names be validated for character set? (e.g., no spaces, no slashes) | Yes (reject invalid names) vs no | Recommend: **yes**, restrict to `[a-z0-9_-]+` to keep filenames safe |
+| Q3 | Should excluded dependencies be completely absent from the packaged `manifest.yml`? | Absent (cleaner, smaller manifest) vs present with a flag | Recommend: **absent** — a smaller manifest also means faster version resolution at staging time |
+| Q4 | Should `packaging_profiles` entries be validated at `buildpack-packager summary` time even when not building? | Yes (catches stale exclusion lists) vs no | Recommend: **yes**, warn if a profile excludes a name not in `dependencies` |
+| Q5 | Should we also support `include` lists in profiles (whitelist model in manifest.yml)? | Yes (more explicit) vs no (requires updating all profiles when a new dep is added) | Recommend: **no for now** — the CLI `--include` flag covers the override use case without complicating the manifest schema |
diff --git a/docs/spring-auto-reconfiguration-migration.md b/docs/spring-auto-reconfiguration-migration.md
new file mode 100644
index 0000000000..52e7f4e541
--- /dev/null
+++ b/docs/spring-auto-reconfiguration-migration.md
@@ -0,0 +1,567 @@
+# Migration Guide: Spring Auto-reconfiguration to java-cfenv
+
+This guide provides step-by-step instructions for migrating from the deprecated **Spring Auto-reconfiguration** framework to **java-cfenv**.
+
+> **Note — the `cloud` Spring profile**
+>
+> Spring Auto-reconfiguration activated a Spring profile named `cloud`. java-cfenv only
+> activates that profile if the `java-cfenv-all` module is on the classpath (it contains
+> `CloudProfileApplicationListener`); the `java-cfenv-boot` module does **not**. If your
+> application relies on the `cloud` profile — for example `application-cloud.yml` /
+> `application-cloud.properties` or `@Profile("cloud")` beans — either use `java-cfenv-all`,
+> or activate it explicitly. If the application already sets other active profiles, use
+> `SPRING_PROFILES_INCLUDE` to add `cloud` alongside them:
+>
+> ```bash
+> cf set-env SPRING_PROFILES_INCLUDE cloud # adds 'cloud' to any existing profiles
+> cf restage
+> ```
+>
+> Use `SPRING_PROFILES_ACTIVE=cloud` only if `cloud` should be the sole active profile (it
+> replaces any others).
+
+> **Note — controlling the automatic behaviour**
+>
+> When the application does not bundle java-cfenv itself, the buildpack injects `java-cfenv-all`
+> (property mapping **and** `cloud` profile). To scope this:
+> - `cf set-env JBP_CONFIG_JAVA_CF_ENV '{enabled: false}'` (+ `cf restage`) disables the
+> **whole** framework — both property mapping and the `cloud` profile. There is no
+> `cloud`-profile-only toggle.
+> - Because the buildpack backs off when the app already bundles a `java-cfenv*.jar`, bundling your
+> own artifact wins: `java-cfenv-boot` = property mapping without the `cloud` profile;
+> `java-cfenv` (core) = neither, use the `CfEnv` API directly.
+>
+> See [Java CfEnv Framework](framework-java-cfenv.md) for details.
+
+> **Note — backwards compatible with buildpack 4.x (java-buildpack 5.0.6+)**
+>
+> As of java-buildpack **5.0.6**, the buildpack injects `java-cfenv-all` by default, so the `cloud`
+> profile activation and the `VCAP_SERVICES` → Spring property mapping behave the same as under
+> java-buildpack 4.x. Apps that relied on either under 4.x keep working after upgrading — no
+> application change is required for the `cloud`/VCAP behaviour. (Buildpack 5.0.0–5.0.5 shipped the
+> bare `java-cfenv` core module, which activated neither; see #1349.)
+
+---
+
+## Table of Contents
+
+1. [Why Migrate?](#why-migrate)
+2. [What Changes?](#what-changes)
+3. [Migration Steps](#migration-steps)
+4. [Service-Specific Migration](#service-specific-migration)
+5. [Testing Your Migration](#testing-your-migration)
+6. [Troubleshooting](#troubleshooting)
+7. [Rollback Plan](#rollback-plan)
+
+---
+
+## Why Migrate?
+
+**Spring Auto-reconfiguration is deprecated** and disabled by default as of December 2025 because:
+
+1. **Spring Cloud Connectors** (the underlying library) entered maintenance mode in July 2019
+2. **No security updates** or bug fixes will be provided
+3. **Not compatible** with Spring Boot 3.x
+4. **java-cfenv** is the official replacement recommended by Pivotal/VMware
+
+**Timeline**:
+- **July 2019**: Spring Cloud Connectors deprecated
+- **December 2025**: Spring Auto-reconfiguration disabled by default
+- **Future**: Spring Auto-reconfiguration will be removed entirely
+
+---
+
+## What Changes?
+
+### Spring Auto-reconfiguration (Old)
+
+```xml
+
+
+```
+
+**How it worked**:
+- Buildpack injected `spring-cloud-cloudfoundry-connector` at runtime
+- Automatically replaced Spring beans with Cloud Foundry-bound services
+- No application code changes required
+
+### java-cfenv (New)
+
+```xml
+
+
+ io.pivotal.cfenv
+ java-cfenv-all
+
+ 3.5.1
+
+```
+
+**How it works**:
+- You add `java-cfenv` dependency to your application
+- Library reads `VCAP_SERVICES` and sets Spring Boot properties
+- Spring Boot autoconfiguration uses these properties
+- More transparent and Spring Boot native
+- `java-cfenv-all` bundles the property post-processors **and** the `cloud` profile listener (`CloudProfileApplicationListener`); use the lighter `java-cfenv-boot` instead only if you do not rely on the `cloud` profile
+
+---
+
+## Migration Steps
+
+### Step 1: Verify Your Spring Boot Version
+
+java-cfenv requires **Spring Boot 2.1+** (Spring Boot 3.x recommended).
+
+Check your `pom.xml` or `build.gradle`:
+
+```xml
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.2.0
+
+```
+
+**If you're on Spring Boot 1.x**: Upgrade to Spring Boot 2.x or 3.x first.
+
+---
+
+### Step 2: Add java-cfenv Dependency
+
+#### Maven (pom.xml)
+
+```xml
+
+
+
+