Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions docs/container-java_main.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,25 @@ If the application uses Spring, [Spring profiles][] can be specified by setting

If `java_main_class` is set to one of Spring Boot's launchers (`JarLauncher`, `PropertiesLauncher` or `WarLauncher`), the Java Main Container sets `SERVER_PORT=$PORT` so that the application binds to the CF-assigned port.

## CF Tasks

The buildpack emits both `web` and `task` process types with the same command so `cf run-task` works without `--command`.

To run a task with a different main class (batch job, migration, etc.), set `java_main_class` to Spring Boot's `PropertiesLauncher` at staging time:

```yaml
env:
JBP_CONFIG_JAVA_MAIN: '{java_main_class: "org.springframework.boot.loader.launch.PropertiesLauncher"}'
Comment on lines +32 to +36
```

Then override the main class per task at run time (requires CF CLI v7+):

```bash
cf run-task my-app --env JAVA_OPTS="-Dloader.main=com.example.BatchJob"
```

`-Dloader.main` is a Spring Boot `PropertiesLauncher` system property -- the buildpack passes it through to the JVM unchanged. `JBP_CONFIG_JAVA_MAIN` is a staging-time setting that applies to both `web` and `task`; `-Dloader.main` is a per-task runtime override.

## Configuration
For general information on configuring the buildpack, including how to specify configuration values through environment variables, refer to [Configuration and Extension][].

Expand Down
13 changes: 13 additions & 0 deletions docs/container-spring_boot.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@ The container expects to run the application creating by running [`gradle distZi

If the application uses Spring, [Spring profiles][] can be specified by setting the [`SPRING_PROFILES_ACTIVE`][] environment variable. This is automatically detected and used by Spring. The Spring Auto-reconfiguration Framework will specify the `cloud` profile in addition to any others.

## CF Tasks

The buildpack includes a `task` process type in the release output using the same command as `web`, so `cf run-task` works without an explicit `--command`.

```bash
cf run-task my-app # uses the task process type command
cf run-task my-app --command "..." # explicit override
```

To run a task with a different main class (batch job, migration, etc.), see [Java Main Container - CF Tasks][java-main-tasks].

[java-main-tasks]: container-java_main.md#cf-tasks

## Configuration
The Spring Boot Container cannot be configured.

Expand Down
6 changes: 3 additions & 3 deletions docs/debugging-the-buildpack.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ Sometimes logging just isn't going to cut it for debugging. There are times when

### Requirements

The buildpack API consists of three bash scripts. This means that if you've got a Unix like environment with Ruby installed at an appropriate level, a filesystem that looks like what Cloud Foundry will present to the buildpack and a local copy of your buildpack, you can run the bash scripts locally.
The buildpack API consists of bash scripts. This means that if you've got a Unix like environment with a filesystem that looks like what Cloud Foundry will present to the buildpack and a local copy of your buildpack, you can run the bash scripts locally.

### Example invocation

Expand All @@ -110,7 +110,7 @@ $ $BUILDPACK_ROOT/bin/compile . $TMPDIR
-----> Downloading Play Framework Auto Reconfiguration 1.4.0_RELEASE from https://java-buildpack.cloudfoundry.org/auto-reconfiguration/auto-reconfiguration-1.4.0_RELEASE.jar (found in cache)
-----> Downloading Spring Auto Reconfiguration 1.4.0_RELEASE from https://java-buildpack.cloudfoundry.org/auto-reconfiguration/auto-reconfiguration-1.4.0_RELEASE.jar (found in cache)

$ $BUILDPACK_ROOT/bin/release . | ruby -e "require \"yaml\"; puts YAML.load(STDIN.read)[\"default_process_types\"][\"web\"]"
$ $BUILDPACK_ROOT/bin/release . | sed -n "s/^ web: '\\(.*\\)'$/\\1/p" | sed "s/''/'/g; s/exec //"
PATH=$PWD/.java-buildpack/open_jdk_jre/bin:$PATH JAVA_HOME=$PWD/.java-buildpack/open_jdk_jre $PWD/play-application-1.0.0.BUILD-SNAPSHOT/bin/play-application -J-Djava.io.tmpdir=$TMPDIR -J-XX:MaxPermSize=64M -J-XX:PermSize=64M -J-javaagent:$PWD/.java-buildpack/app_dynamics_agent/javaagent.jar -J-Dappdynamics.agent.applicationName='' -J-Dappdynamics.agent.tierName='Cloud Foundry' -J-Dappdynamics.agent.nodeName=$(expr "$VCAP_APPLICATION" : '.*instance_id[": ]*"\([a-z0-9]\+\)".*') -J-Dappdynamics.agent.accountAccessKey=[REDACTED] -J-Dappdynamics.agent.accountName=[REDACTED] -J-Dappdynamics.controller.hostName=[REDACTED] -J-Dappdynamics.controller.port=443 -J-Dappdynamics.controller.ssl.enabled=true -J-Dhttp.port=$PORT
```

Expand All @@ -131,7 +131,7 @@ Running the different stages of the buildpack lifecycle can be made simpler with
```bash
$ alias detect='$BUILDPACK_ROOT/bin/detect .'
$ alias compile='$BUILDPACK_ROOT/bin/compile . $TMPDIR'
$ alias release='$BUILDPACK_ROOT/bin/release . | ruby -e "require \"yaml\"; puts YAML.load(STDIN.read)[\"default_process_types\"][\"web\"]" | sed "s| exec||"'
$ release() { $BUILDPACK_ROOT/bin/release . | sed -n "s/^ web: '\\(.*\\)'$/\\1/p" | sed "s/''/'/g; s/exec //"; }
```

[d]: extending-logging.md#configuration
4 changes: 2 additions & 2 deletions src/integration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ Switchblade is a Go-based integration testing framework that supports both Cloud
First, create a buildpack zip file:

```bash
bundle exec rake package
./scripts/package.sh
```

This will create a file like `java-buildpack-v4.x.x.zip` in the project root.
This will create `build/buildpack.zip` in the project root.
Comment on lines 24 to +30

### Run Integration Tests

Expand Down
4 changes: 3 additions & 1 deletion src/java/finalize/finalize.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,12 @@ func (f *Finalizer) writeReleaseYaml(container containers.Container) error {
}

releaseYamlPath := filepath.Join(tmpDir, "java-buildpack-release-step.yml")
escapedCommand := strings.ReplaceAll(fullCommand, "'", "''")
yamlContent := fmt.Sprintf(`---
default_process_types:
web: '%s'
`, fullCommand)
task: '%s'
`, escapedCommand, escapedCommand)

if err := os.WriteFile(releaseYamlPath, []byte(yamlContent), 0644); err != nil {
return fmt.Errorf("failed to write release YAML: %w", err)
Expand Down
52 changes: 49 additions & 3 deletions src/java/finalize/finalize_test.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package finalize_test

import (
"github.com/cloudfoundry/java-buildpack/src/internal/mocks"
"github.com/golang/mock/gomock"
"os"
"path/filepath"
"regexp"
"time"

"github.com/cloudfoundry/java-buildpack/src/internal/mocks"
"github.com/cloudfoundry/java-buildpack/src/java/finalize"
"github.com/cloudfoundry/libbuildpack"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"gopkg.in/yaml.v2"
)

var _ = Describe("Finalize", func() {
Expand Down Expand Up @@ -99,7 +101,7 @@ dependencies: []

// Create META-INF/MANIFEST.MF with corresponding content of a Spring Boot app
manifestFile := filepath.Join(buildDir, "META-INF", "MANIFEST.MF")
Expect(os.WriteFile(manifestFile, []byte("Spring-Boot-Version: 3.x.x"), 0644)).To(Succeed())
Expect(os.WriteFile(manifestFile, []byte("Spring-Boot-Version: 4.x.x"), 0644)).To(Succeed())

finalizer.JREName = "OpenJDK"
finalizer.ContainerName = "Spring Boot"
Expand Down Expand Up @@ -243,6 +245,50 @@ dependencies: []
})
})

Describe("Release YAML", func() {
BeforeEach(func() {
os.Setenv("JBP_CONFIG_JAVA_MAIN", "{java_main_class: com.example.App}")
finalizer.JREName = "OpenJDK"
finalizer.ContainerName = "Java Main"
})

AfterEach(func() {
os.Unsetenv("JBP_CONFIG_JAVA_MAIN")
})
Comment on lines +248 to +257

It("emits web and task process types with identical commands", func() {
Expect(finalize.Run(finalizer)).To(Succeed())
content, err := os.ReadFile(filepath.Join(buildDir, "tmp", "java-buildpack-release-step.yml"))
Expect(err).NotTo(HaveOccurred())

re := regexp.MustCompile(`(?m)^\s+(web|task):\s+'(.+)'$`)
matches := re.FindAllStringSubmatch(string(content), -1)
Expect(matches).To(HaveLen(2), "expected both web and task process types")

commands := map[string]string{}
for _, m := range matches {
commands[m[1]] = m[2]
}
Expect(commands).To(HaveKey("web"))
Expect(commands).To(HaveKey("task"))
Expect(commands["web"]).To(Equal(commands["task"]))
})

It("escapes single quotes in commands so release YAML is valid", func() {
os.Setenv("JBP_CONFIG_JAVA_MAIN", `{java_main_class: com.example.App, arguments: "--message=it's alive"}`)
Expect(finalize.Run(finalizer)).To(Succeed())
content, err := os.ReadFile(filepath.Join(buildDir, "tmp", "java-buildpack-release-step.yml"))
Expect(err).NotTo(HaveOccurred())

var parsed struct {
DefaultProcessTypes map[string]string `yaml:"default_process_types"`
}
Expect(yaml.Unmarshal(content, &parsed)).To(Succeed(), "release YAML must be valid")
Expect(parsed.DefaultProcessTypes["web"]).To(ContainSubstring("it's alive"))
Expect(parsed.DefaultProcessTypes["task"]).To(ContainSubstring("it's alive"))
})
})

Describe("javaexec launcher installation", func() {
It("installs launcher from buildpack bin/ for packaged buildpack usage", func() {
// Default path: <buildpackDir>/bin/javaexec already written in BeforeEach.
Expand Down