Skip to content

Foundations

Project Structure & Build

Everything you need to go from an empty folder to a running Kestros project: start an instance with Docker, install the Java and Maven tooling, scaffold a project with the Kestros Maven archetype, and build and deploy it. This page covers the generated module layout and the build profiles that push each part of a project to your instance.

Running Kestros

The Quick Start covers this in brief; this page is the full reference.

The quickest way to run Kestros locally is with Docker and Docker Compose. Install Docker and Docker Compose first. On an Apple Silicon Mac, OrbStack is a good alternative Docker runtime.

Create an empty folder and add a file named kestros.yaml with the following contents:

kestros.yaml
services:
  kestros:
    image: kestros/kestros-pro-dev:0.9.0   # or desired version
    container_name: kestros-pro-dev        # or desired tier
    restart: unless-stopped
    volumes:
      - ./launcher:/opt/kestros/launcher   # optional
      - ./logs:/opt/kestros/launcher/logs
    ports:
      - 8080:8080

Then start the instance from that folder:

terminal
$ docker compose -f kestros.yaml up
A few things that come up in practice: if Compose complains about formatting, reformat the file and try again. If you hit a platform mismatch, add platform: linux/amd64 under the service. The first build can take a minute or two while images are pulled, so give it a moment before assuming something is wrong.

Debug mode

To run the instance with a remote debugger attached, add a JAVA_OPTS environment variable to the service:

kestros.yaml (debug)
environment:
  JAVA_OPTS: "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:30303"

Installing Maven and Java

Building a Kestros project needs a Java Development Kit and Maven. Kestros supports the following versions:

  • Java version 11 or higher
  • Maven version 3.x

Any Java IDE works for development. If you use IntelliJ IDEA, you can attach the debugger using the same JVM arguments shown in the Debug mode section above.

Creating a project

The Quick Start covers this in brief; this page is the full reference.

Kestros projects are scaffolded from a Maven archetype. Run archetype:generate against the Kestros project archetype to generate a new project interactively:

terminal
$ mvn archetype:generate \
  -DarchetypeGroupId=io.kestros.cms \
  -DarchetypeArtifactId=kestros-project-archetype \
  -DarchetypeVersion=0.9.0 -U

Maven then prompts for each project parameter. To run the same generation non-interactively, pass every parameter on the command line, including two that are easy to miss: artifactIdNoSpecialCharacters and artifactIdShorthand.

terminal (non-interactive)
$ mvn -B archetype:generate \
  -DarchetypeGroupId=io.kestros.cms -DarchetypeArtifactId=kestros-project-archetype \
  -DarchetypeVersion=0.9.0 \
  -DgroupId=com.example -DartifactId=mysite -Dversion=0.0.1-SNAPSHOT \
  -DartifactName=mysite -DartifactDescription=mysite -DorganizationName=Example \
  -DartifactIdNoSpecialCharacters=mysite -DartifactIdShorthand=ms \
  -DhasParentProject=n -DhashSymbol="#"

Archetype parameters

Each parameter the archetype asks for is described below.

ParameterDescription
groupIdRoot level package name. No spaces and no special characters.
artifactIdUnique ID for the project, used to name the project and compiled files. No spaces and no special characters; hyphens are allowed.
artifactIdNoSpecialCharactersThe artifactId with any special characters, such as hyphens, removed. Defaults to artifactId.
artifactIdShorthandShort project ID used to name the initial UI Libraries and UI Frameworks. No spaces and no special characters.
versionInitial Maven project version. Can be left blank; defaults to 1.0-SNAPSHOT. A value like 1.0.0-SNAPSHOT or 0.0.1-SNAPSHOT is recommended.
packageJava package. Can be left blank; defaults to the groupId value. Leave it at the default (see the note above).
artifactNameProject title for metadata. Defaults to artifactId.
artifactDescriptionProject description for metadata.
organizationNameOrganization name for metadata.
hasParentProjectWhether the generated modules nest under an existing parent project. Defaults to false.
hashSymbolA literal # for the generated templates (Velocity reserves #). Defaults to #; leave it at the default.

Generated project modules

The archetype generates a parent project with four modules. Each module has a clear responsibility, which keeps interfaces, logic, UI, and sample content separated:

ModuleContents
apiJava interfaces and exceptions. Keeping these separate lets you change an implementation without touching every dependent.
coreServices and their implementations, and general-purpose Sling Model implementations. (Component and datasource Sling Models live with their components in application, not here.) Core does not depend on the component libraries.
applicationThe UI Frameworks, UI Libraries (Vendor Libraries), custom components and their component views and Sling Models, the datasource models, and page templates.
contentSample site content for reference.

How they depend on each other: api is the base (interfaces only); both core and application depend on api; content holds no Java at all, just JCR content. So a change to an interface in api can ripple into both core and application, which is exactly why the interfaces are kept in their own module.

The generated application module ships some things twice on purpose, as examples of both styles: an unversioned form and a versioned form of the UI Framework, the UI Library, and the sample component’s view (for example <artifactId>-framework alongside <artifactId>-versioned-framework). The sample site wires up the unversioned ones; the versioned copies are there to show the managed/versioned layout (see UI Libraries and UI Frameworks & Themes for the difference). You can delete whichever style you are not using.

For more on what lives in the application module, see Components and UI Frameworks & Themes.

Building and deploying

The Quick Start covers this in brief; this page is the full reference.

A plain mvn clean install only builds the project; it does not deploy anything to a running instance. To deploy, activate the install profiles with Maven's -P flag. A full deploy of every part of a project looks like this:

terminal
$ mvn clean install -PinstallBundle,installPackage,installContent

You can activate a single profile the same way, for example to deploy only the bundles:

terminal
$ mvn clean install -PinstallBundle

The available build profiles are:

ProfileDescription
installBundleInstalls the api and core bundles.
installPackageInstalls the application package and bundle.
installContentInstalls the content package.
strictRuns the build with Kestros strict checks, including checkstyle, SpotBugs, code coverage, and license-header checks.
Package installs are asynchronous. A BUILD SUCCESS means the package was uploaded and the install job was queued; the actual import runs a moment later on a background thread. Check that content exists a few seconds after the build finishes, not the instant it reports success.
Before installing a content package, the build waits for every bundle to become active, up to several minutes. If any bundle is stuck, that wait is paid in full on each install. Pass -Dvault.bundleStatusWaitLimit=1 to cap the wait at one second and skip the delay.

Overriding build parameters

The install profiles target a local instance by default. Override any of the connection settings with the corresponding -D property:

PropertyUsageDefault
sling.host-Dsling.host=localhost
sling.port-Dsling.port=8080
sling.protocol-Dsling.protocol=http
sling.username-Dsling.username=admin
sling.password-Dsling.password=admin