blob: b62b55f304efdf7d606e00f4f11b31810b5692a1 [file] [log] [blame]
= SimpleApp
:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
The quickest way to get started building an application "for real" is to use the `simpleapp` starter app.
There are two variations of the application (and so two branches in the git repo).
One variation uses JPA as the ORM, the other uses JDO, so you can focus on whichever ORM you prefer.
The application is also built nightly as a docker image, so you can quickly try it out:
[source,bash,subs="attributes+"]
----
docker run -d -p 8080:8080 apache/causeway-app-simpleapp:v{fwk-version}-jpa-SNAPSHOT
----
Replace "v{fwk-version}-jpa" with "v{fwk-version}-jdo" if using the JDO ORM.
As with the xref:docs:starters:helloworld.adoc[HelloWorld] starter app, the instructions <<Downloading & Running,below>> will download a minimal Apache Causeway app consisting of a single entity (`SimpleObject`) with supporting domain services.
However, unlike HelloWorld, this app also provides more structure to assist you as your application grows, with business logic placed in a separate Maven module (`simpleapp-...-module-simple`) to the module that bootstraps the webapp (`simpleapp-...-webapp`).
Replace "..." with either "jpa" or "jdo", as appropriate.
The idea is that as your application grows in scope that you put each new area of functionality in its own module (copy-n-paste the `simpleapp-...-module-simple` module).
These modules can depend on each other, but Maven will to ensure that dependencies between these areas of functionality are unidirectional.
In this way your application will be a "modular monolith"; said another way it will prevent your application from degenerating into a link:https://en.wikipedia.org/wiki/Big_ball_of_mud[big ball of mud].
See also the discussion <<structure-of-the-app,below>>.
The application also includes examples of unit tests and integration tests.
You'll find these in their own Maven modules (`simpleapp-...-module-simple-tests` and `simpleapp-...-webapp-tests`).
Normally we recommend that tests should be in the same Maven module as the code that they exercise.
The simpleapp doesn't do it this way just to give you the option to exclude them while initially prototyping/exploring a domain.
You can use them as a reference once your ideas have solidifid and you need to start writing proper "production" code.
== Prerequisites
Apache Causeway is a Java based framework, so in terms of prerequisites, you'll need to install:
* Java {jdk-version} JDK (or later)
+
Apache Causeway v{fwk-version} requires Java {fwk-jdk-version}, and the simpleapp itself is currently configured for Java {jdk-version}.
* link:http://maven.apache.org[Apache Maven] 3.9.7+
If using JDO as the ORM, you'll also need to run the Datanucleus enhancer (this post-processes the byte code of the entities).
The xref:setupguide:ROOT:about.adoc[Setup Guide] explains how to do this for either IntelliJ and Eclipse.
If using JPA as the ORM, the equivalent process to enhancement is performed at run-time, so there are no special setup considerations.
== Downloading & Running
Create a new directory, and `cd` into that directory.
To build the app from the latest stable release:
* if using JDO as the ORM:
+
include::simpleapp-script-jdo.adoc[]
* if using JPA as the ORM:
+
include::simpleapp-script-jpa.adoc[]
Either way, this should only take a few seconds to download, compile and run.
Then browse to link:http://localhost:8080[], and read on.
[#using-the-app]
== Using the App
When you start the app, you'll be presented with a welcome page from which you can access the webapp using either the generic UI provided by xref:vw:ROOT:about.adoc[Web UI (Wicket viewer)] or use Swagger to access the xref:vro:ROOT:about.adoc[REST API (Restful Objects viewer)]:
image::simpleapp/using/010-root-page.png[width="600px"]
Choose the generic Wicket UI, and navigate to the login page:
image::simpleapp/using/020-login-to-wicket-viewer.png[width="600px"]
The app itself is configured to run using xref:security:ROOT:about.adoc[shiro security], as configured in the `shiro.ini` config file.
You can login with:
* username: _sven_
* password: _pass_
=== Wicket viewer
Once you've logged in you'll see the default home page:
image::simpleapp/using/030-home-page.png[width="600px"]
This is a view model annotated with xref:refguide:applib:index/annotation/HomePage.adoc[@HomePage]:
[source,java]
.HomePageViewModel.java
----
@Named("domainapp.HomePageViewModel")
@DomainObject( nature = Nature.VIEW_MODE )
@HomePage
public class HomePageViewModel {
public String title() { // <.>
return return getObjects().size() + " objects";
}
public List<SimpleObject> getObjects() { // <.>
return simpleObjects.listAll();
}
@Inject SimpleObjects simpleObjects; // <.>
}
----
<.> identifies or describes the object
<.> collection of objects shown on the page
<.> automatically injected by the framework
[#fixtures]
==== Fixtures
When prototyping against an in-memory database, it's useful to have a mechanism to create some initial state.
This can be done using fixture scripts, accessible from the menu:Prototyping[Run Fixture Script]:
image::simpleapp/using/032-run-fixture-script-prompt.png[width="600px"]
This brings up a dialog to select the fixture script:
image::simpleapp/using/033-run-fixture-script-prompt.png[width="600px"]
The "Domain App Demo" in the drop-down refers to this code:
[source,java]
.DomainAppDemo.java
----
public class DomainAppDemo extends FixtureScript {
@Override
protected void execute(final ExecutionContext ec) {
ec.executeChildren(this,
moduleWithFixturesService.getTeardownFixture()); // <.>
ec.executeChild(this,
new SimpleObject_persona.PersistAll()); // <.>
}
@Inject ModuleWithFixturesService moduleWithFixturesService;
}
----
<.> uses injected service to tear down all objects.
(Each module provides a teardown script; these are run in the correct sequence).
<.> Creates new objects
When executed, all objects created by the fixture are listed:
image::simpleapp/using/034-run-fixture-script-result.png[width="600px"]
Navigating back to the home page shows the newly created objects:
image::simpleapp/using/036-home-page-after-fixture-scriptpng.png[width="600px"]
As well as running in fixtures from the UI, you can also specify a configuration property to run a fixture script as part of the application start-up:
[source,ini]
.config/application.properties
----
# causeway.testing.fixtures.initial-script = \
# domainapp.webapp.application.fixture.scenarios.DomainAppDemo
----
==== Create an object
You can also of course create new objects:
image::simpleapp/using/040-create-object-from-menu.png[width="600px"]
To avoid obscuring the current page, this is configured to bring up a sidebar dialog:
image::simpleapp/using/050-create-object-from-menu-prompt.png[width="600px"]
Hitting OK returns the created object:
image::simpleapp/using/060-created-object.png[width="600px"]
The above functionality is implemented by this code (in the `SimpleObjects` menu domain service):
[source,java]
----
@Action(semantics = SemanticsOf.NON_IDEMPOTENT) // <.>
@ActionLayout(promptStyle = PromptStyle.DIALOG_SIDEBAR) // <.>
public SimpleObject create(
@Name final String name) { // <.>
return repositoryService.persist(SimpleObject.ofName(name));
}
----
<.> Specifying semantics is recommended, as it changes the HTTP method that is used if the action is invoked through the xref:vro::about.adoc[REST API].
<.> Prompt styles such as modal or sidebar can be specified per action, or globally in `application.yml` file.
<.> The `@Name` annotation is actually a meta-annotation, meaning that a number of additional semantics (length, layout, validation etc.) are inferred.
==== Invoke an action
The `SimpleObject` contains a couple of properties, and a single action to update that property.
The `name` property is read-only, and can only be modified using the `updateName` action:
image::simpleapp/using/070-update-name.png[width="600px"]
The above functionality is implemented by this code (in the `SimpleObject` entity):
[source,java]
----
@Action(semantics = IDEMPOTENT, commandPublishing = Publishing.ENABLED, executionPublishing = Publishing.ENABLED)
@ActionLayout(
associateWith = "name", promptStyle = PromptStyle.INLINE,
describedAs = "Updates the name of this object, certain characters (" + PROHIBITED_CHARACTERS + ") are not allowed."
)
public SimpleObject updateName(
@Name final String name) {
setName(name);
return this;
}
public String default0UpdateName() {
return getName();
}
----
==== Edit a property
The `notes` property is editable, and can be edited in-place.
For example:
image::simpleapp/using/080-edit-notes.png[width="600px"]
==== Actions requiring confirmations
It's also possible to delete an object:
image::simpleapp/using/090-delete-object.png[width="600px"]
The viewer displays a message confirming that the object has been deleted:
image::simpleapp/using/100-object-deleted.png[width="600px"]
The above functionality is implemented by this code (in the`SimpleObject` entity):
[source,java]
----
@Action(semantics = NON_IDEMPOTENT_ARE_YOU_SURE) // <.>
public void delete() {
final String title = titleService.titleOf(this); // <.>
messageService.informUser(String.format("'%s' deleted", title));
repositoryService.removeAndFlush(this);
}
----
<.> Requires the user to confirm the action
<.> The action's implementation uses three services provided by the framework; these are injected into the domain object automatically.
=== Swagger (Restful Objects)
CAUTION: if invoking an action using Swagger returns a 401 (unauthorised), then navigate to the REST API directly (link:http://localhost:8080/restful[] to authenticate the browser first]).
Using menu:Prototyping[Open Swagger UI] menu item (or just going back to the home page at link:http://localhost:8080[localhost:8080]) we can use link:https://swagger.io/[Swagger UI] as a front-end to the REST API provided by the Restful Objects viewer.
image::simpleapp/using/200-swagger-ui-before-reload.png[width="600px"]
The public API (where the calling client is assumed to be 3rd party) only exposes view models, not entities.
If the API is private (or for prototyping), then resources corresponding to entities are also exposed:
image::simpleapp/using/210-simpleapp-resources.png[width="600px"]
For example, an object can be created using the resource that represents the `SimpleObjects#create` action:
image::simpleapp/using/220-create-object-thru-rest-api.png[width="600px"]
The response indicates that the object was successfully created:
image::simpleapp/using/230-create-object-thru-rest-api-response.png[width="600px"]
The Swagger UI also provides a resource to retrieve any object:
image::simpleapp/using/240-retrieve-object-using-rest-api.png[width="600px"]
This results in a representation of the domain object (as per the requested `Response Content Type`, ie `ACCEPT` header):
image::simpleapp/using/250-retrieve-object-using-rest-api-response.png[width="600px"]
The Swagger UI is provided as a convenience; the REST API is actually a complete hypermedia API (in other words you can follow the links to access all the behaviour exposed in the regular Wicket app).
The REST API implemented by Apache Causeway is specified in the link:http://www.restfulobjects.org[Restful Object spec].
[#structure-of-the-app]
== Structure of the App
The simpleapp starter app is a multi-module project, structured so that you easily extend it as your application grows.
=== Application Modules
The application consists of five modules:
[plantuml]
.simpleapp dependencies
----
[webapp-...-tests] <<maven module>> #LightBlue
[webapp-...] <<maven module>>
[module-...-simple-tests] <<maven module>> #LightBlue
[module-...-simple] <<maven module>>
[webapp-...-tests] .l-> [webapp-...]
[module-...-simple-tests] .l-> [module-...-simple]
[webapp-...] .u-> [module-...-simple]
----
where "..." is either "jdo" or "jpa", depending on the branch.
The main business logic resides in `module-...-simple`, with the `webapp` module acting as an aggregator.
Each of these modules have unit and/or integration tests.
To allow them to be easily excluded (while prototyping/exploration), they have been placed into their own respective modules.
The (non-test) Maven modules each contain exactly one link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html[@Configuration] class, residing at the package root for that Maven module.
The location of this class is used for classpath scanning.
In a larger application there would likely be many more modules containing these domain object modules.
For example, you might have a `module-customer` holding a `Customer` entity and related entities/services, a `module-product` holding a `Product` catalog, and a `module-order` to hold the ``Order``s placed by ``Customer``s:
[plantuml]
.Typical application dependencies
----
[webapp] <<maven module>>
[module-order] <<maven module>>
[module-customer] <<maven module>>
[module-product] <<maven module>>
[webapp] .u-> [module-order]
[module-order] .u-> [module-customer]
[module-order] .u-> [module-product]
----
We can use Maven dependency management to ensure that there are no cyclic dependencies (order "knows about" product but product does not know about orders) and ensure that the codebase remains decoupled.
If Java9 modules become commonplace, we'll also be able to restrict visibility of classes between modules.
=== Bootstrapping & Framework Modules
One of the main responsibilities of Spring Boot is - naturally enough - to bootstrap the application.
For the webapp, this is done using a class annotated with link:https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/SpringBootApplication.html[@SpringBootApplication].
For integration tests, this uses the link:https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/context/SpringBootTest.html[@SpringBootTest] annotation.
These two different annotations reference a (class annotated with) link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html[@Configuration], which in turn can link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Import.html[@Import] other annotations.
By convention, the top-level `@Configuration` in an Apache Causeway application is called the "app manifest".
The link:{attachmentsdir}/simpleapp-modules-dependencies.pptx[diagram] below shows how classes fit together:
.Module Dependencies
image::simpleapp/simpleapp-modules-dependencies.png[width="800px"]
(For a JPA branch, the `JdoDataNucleus5` dependency is replaced by `JpaEclipseLink`).
Let's now review the contents of each of the modules in the simpleapp starter app.
=== module-...-simple's src/main/java
Under `src/main/java` we have:
[source]
----
src/main/java/
domainapp/ <!--.-->
modules/
simple/ <!--.-->
dom/ <!--.-->
so/ <!--.-->
SimpleObject.java
SimpleObject.layout.xml
SimpleObject.png
SimpleObjectRepository.java <!--.-->
SimpleObjects.java
fixture/ <!--.-->
SimpleObject_persona.java
SimpleObjectBuilder.java
types/ <!--.-->
Name.java
Notes.java
SimpleModule.java <!--.-->
META-INF/
persistence.xml <!--.-->
----
<.> For simplicity, all the Java source files reside in a `domainapp` top-level package.
Change as required.
<.> Top level package for the 'simple' module.
<.> The `dom` subpackage holds the "domain object model" for this module.
Modules may have other subpackages, common ones include ``types`` and ``fixture``s (as below), also ``api``s, ``contribution``s, ``spi``s
<.> Holds classes for the `so` ("simple object") entity/aggregate, consisting of the entity definition itself (`SimpleObject`) and a corresponding domain services (`SimpleObjects` and `SimpleObjectRepository`).
The associated `.layout.xml` and `.png` are optional but provide metadata/resources for rendering (Maven is configured to also treat `src/main/java` as a resource location).
<.> For the `jpa` branch only, uses Spring Data JPA to automatically provide the query implementation.
<.> The `fixture` package contains classes to set up the database to an initial state (as described xref:#fixtures[earlier].
One of the classes is a `FixtureScript` (defines _how_ to set up the data) the other is a persona enum (defines _what_ data to set up).
<.> The `types` package contains meta-annotations to describe the usage of common value types such as ``String``s.
<.> `SimpleModule` is a Spring link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html[@Configuration] which allows the domain services and entities of the module to be located. +
This is discussed in more detail below.
<.> For the `jdo` branch only, the `persistence.xml` file is required boilerplate.
==== SimpleModule
Every module within an Apache Causeway application should have a module class.
Its purpose is to define a package to scan from, and optionally to declare any transitive dependencies.
In the case of `SimpleModule`, it consists of:
[source,java]
.SimpleModule.java
----
package domainapp.modules.simple;
... imports omitted ...
@Configuration
@Import({}) // <.>
@ComponentScan // <.>
@EnableJpaRepositories // <.>
@EntityScan(basePackageClasses = {SimpleModule.class}) // <.>
public class SimpleModule
implements ModuleWithFixtures { // <.>
@Override
public FixtureScript getTeardownFixture() {
return new TeardownFixtureAbstract2() {
@Override
protected void execute(ExecutionContext executionContext) {
deleteFrom(SimpleObject.class);
}
};
}
@ConfigurationProperties("app.simple-module") // <.>
@Data
@Validated
public static class Configuration {
private final Types types = new Types();
@Data
public static class Types {
private final Name name = new Name();
@Data
public static class Name {
private final Validation validation = new Validation();
@Data
public static class Validation {
private char[] prohibitedCharacters = "!&%$".toCharArray();
private String message = "Character '{}' is not allowed";
}
}
}
}
}
----
<.> This module has no dependencies.
If there were, these would be expressed in terms of module classes (each being a Spring `@Configuration`)
<.> specifies this class' package as a root to scan for Spring link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Component.html[@Component]s.
<.> for `jpa` branch only, enables Spring Data JPA repositories
<.> for `jpa` branch only, to automatically discover JPA entities
<.> Optionally, modules can implement the testing's `ModuleWithFixtures` interface.
Through this, they can provide a fixture script which can be used to teardown all entities that are "owned" by the module.
Since the module dependency graph is known, this allows all data to be removed, useful for prototyping and sometimes for integration tests.
<.> Spring Boot link:https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-typesafe-configuration-properties[type-safe configuration], as per link:https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/context/properties/ConfigurationProperties.html[@ConfigurationProperties] annotation.
This Spring Boot feature is used by the framework, but can equally easily be used by application code.
The `@Name.Specification` class uses this configuration property.
The scanning mechanism is also leveraged by Apache Causeway to pick up three types of classes:
* all domain services
+
These are classes that are annotated with the framework's xref:refguide:applib:index/annotation/DomainService.adoc[@DomainService] annotation.
Because `@DomainService` is meta-annotated as a `@Component`, these are found automatically and are managed by Spring (ie instantiated, injected etc).
+
Depending on their nature, domain services are used to build up the menu, or are available to call programmatically, eg repositories, or sometimes both.
+
In the simpleapp starter app, the only domain service is `SimpleObjects`.
This appears in the menu, and also acts as a repository for the `SimpleObject` entity.
The `jpa` branch also has the `SimpleObjectRepository` Spring Data service.
* all entities.
+
These are entities that are annotated with both xref:refguide:applib:index/annotation/DomainObject.adoc[@DomainObject] annotation and with the ORM-specific annotation.
For `jdo` branch, this is `@javax.jdo.annotations.PersistenceCapable`; for the `jpa` branch this is `@javax.persistence.Entity`).
+
In the simpleapp starter app, the only entity is `SimpleObject`.
* all fixture scripts
+
These are classes that extend from the testing applib's `FixtureScript` class, and are used to setup the database when running in prototype mode (against an in-memory database).
+
As already discussed, the `fixture` package provides classes to create sample objects, while the `SimpleModule` provides a fixture script to tear down all data from the module.
=== module-...-simple-test's src/test/java
Under `src/test/java` we have:
[source]
----
src/test/java/
domainapp/
modules/
simple/
dom/
so/ <.>
SimpleObject_Test.java
SimpleObjects_Test.java
integtests/
tests/ <.>
SimpleObject_IntegTest.java
SimpleObjects_IntegTest.java
SimpleModuleIntegTestAbstract.java <.>
SimpleModuleIntegTestConfiguration.java <.>
src/test/resources/
application-test.yml <.>
----
<.> These are very simple unit tests of `SimpleObject` and `SimpleObjects` with the package structure the same as in `src/main/java`.
They are written in JUnit 5, and use JMockito as the mocking library.
<.> Integration tests for the module.
These use the xref:refguide:applib:index/services/wrapper/WrapperFactory.adoc[WrapperFactory] to simulate interactions through the UI.
<.> The `SimpleModuleIntegTestAbstract` superclass bootstraps the module's integration tests.
This is discussed in more detail below.
<.> Spring to bootstrap the integration test.
<.> Configuration for the "test" profile
NOTE: these integration tests are annotated with the Spring link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Transactional.html[@Transactional], which means that Spring will automatically roll back the changes to the database; there's no need to delete data afterwards.
IMPORTANT: the naming convention -- with `Test` and `IntegTest` suffixes -- is important, because the Maven surefire plugin is configured to run multiple times, one `<execution>` for each suffix.
[#simplemoduleintegtestabstract]
==== SimpleModuleIntegTestAbstract
The `SimpleModuleIntegTestAbstract` is the superclass of all integration tests in the module, annotated with link:https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/context/SpringBootTest.html[@SpringBootTest]:
[source,java]
.SimpleModuleIntegTestAbstract.java
----
@SpringBootTest(
classes = SimpleModuleIntegTestAbstract.TestApp.class // <.>
)
@ActiveProfiles("test") // <.>
public abstract class SimpleModuleIntegTestAbstract
extends CausewayIntegrationTestAbstractWithFixtures { // <.>
@Configuration
@Import({
CausewayModuleCoreRuntimeServices.class, // <.>
CausewayModuleSecurityBypass.class, // <.>
CausewayModuleJdoDataNucleus5.class, // <.>
CausewayModuleTestingFixturesApplib.class, // <.>
SimpleModule.class // <.>
})
@PropertySources({
@PropertySource(CausewayPresets.H2InMemory_withUniqueSchema), // <.>
@PropertySource(CausewayPresets.DatanucleusAutocreateNoValidate), // <.>
@PropertySource(CausewayPresets.UseLog4j2Test), // <.>
})
public static class TestApp {
}
}
----
<.> The `TestApp` (defined as a nested static class below) lists the modules needed to bootstrap the integration test.
<.> Activates the "test" profile, which reads in additional configuration in `application-test.yml"
<.> Tests typically inherit from `CausewayIntegrationTestAbstract`, which provides some convenience methods to inherit from.
In this case, the test inherits from the `CausewayIntegrationTestAbstractWithFixtures` subclass which also adds in support for running fixtures.
<.> Specifies the modules that make up Apache Causeway framework itself.
These include core, security set to the bypass implementation (effectively is ignored) and JDO/DataNucleus for persistence.
Note that no viewers are bootstrapped because the tests are run through Spring's integration testing framework, rather than (say) as Selenium tests.
<.> Disables security checks.
<.> Configures JDO as the ORM.
+
If using JPA, this would be `CausewayModuleJpaEclipseLink.class` instead.
<.> Brings in support for running fixtures.
+
You can learn more about testing in the xref:testing:ROOT:about.adoc[Testing Guide].
<.> The module containing the actual business logic to be tested.
<.> Runs the tests in memory using H2.
A unique schema allows tests to potentially be run in parallel
<.> Ensures that JDO/DataNucleus is configured to create the database schema first.
This may be required because the application might otherwise be configured to use the xref:userguide:flyway:about.adoc[Flyway integration].
<.> Sets up logging to use the configuration defined in the `log4j2-test.xml` file
=== webapp's src/main/java
Under `src/main/java` we have:
[source]
----
src/main/java/
domainapp/
webapp/
application/
fixture/
scenarios/ <.>
DomainAppDemo.java <.>
services/
health/
HealthCheckServiceImpl.java <.>
homepage/
HomePageViewModel.java <.>
HomePageViewModel.layout.xml
HomePageViewModel.png
ApplicationModule.java <.>
custom/
restapi/
CustomController.class <.>
CustomModule.class
quartz/
job/
SampleJob.class <.>
QuartzModule.class
AppManifest.java <.>
SimpleApp.java <.>
----
<.> Defines scenarios (fixtures) for setting up the system into a known state.
Used for prototyping and also integration testing.
<.> The `DomainAppDemo` is the fixture that was run xref:#fixtures[earlier on].
<.> An implementation of the xref:refguide:applib:index/services/health/HealthCheckService.adoc[HealthCheckService].
This integrates with Spring Boot's link:https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/actuate/health/HealthIndicator.html[HealthIndicator] SPI, surfaced through the link:https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html[Spring Boot Actuator].
<.> Annotated with xref:refguide:applib:index/annotation/HomePage.adoc[@HomePage] and so is shown automatically as the home page.
<.> Defines the services in the webapp module, along with dependencies onto the other modules in the application.
+
Discussed in more detail below.
<.> Demonstrates how to implement a custom REST controller, accessing the domain object model managed by Apache Causeway.
<.> Demonstrates how to run quartz as a background service, accessing the domain object model managed by Apache Causeway.
<.> `AppManifest` is the top-level Spring link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html[@Configuration] that specifies the components of Apache Causeway to use, along with the modules making up the application itself (ie `ApplicationModule`, which depends in turn on `SimpleModule`, and `CustomModule`).
+
This is discussed in more detail below
<.> `SimpleApp` is the link:https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/SpringBootApplication.html[@SpringBootApplication] used to bootstrap the app.
It's pretty much boilerplate - the important piece is that it references `AppManifest`.
+
Discussed in more detail below
==== ApplicationModule
The `ApplicationModule` defines the services in the webapp module, along with dependencies onto the other modules in the application.
It's very simple though:
[source,java]
.ApplicationModule.java
----
package domainapp.webapp.application;
... imports omitted ...
@Configuration
@Import(SimpleModule.class) // <.>
@ComponentScan // <.>
public class ApplicationModule {
}
----
<.> This module depends on the `SimpleModule` module.
<.> specifies this class' package as a root to scan for Spring link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Component.html[@Component]s.
[#appmanifest]
==== AppManifest
The "app manifest" is the top-level Spring `@Configuration`.
It looks like this:
[source,java]
.AppManifest.java
----
@Configuration
@Import({
CausewayModuleCoreRuntimeServices.class, // <.>
CausewayModuleSecurityShiro.class, // <.>
CausewayModuleJpaEclipseLink.class, // <.>
CausewayModuleViewerRestfulObjectsJaxrsResteasy4.class, // <.>
CausewayModuleViewerWicketViewer.class, // <.>
CausewayModuleTestingH2ConsoleUi.class, // <.>
CausewayModuleTestingFixturesApplib.class, // <.>
CausewayModuleExtFlywayImpl.class, // <.>
ApplicationModule.class, // <.>
CustomModule.class, // <9>
QuartzModule.class, // <9>
DomainAppDemo.class // <.>
})
@PropertySources({
@PropertySource(CausewayPresets.DebugDiscovery), // <.>
})
public class AppManifest {
}
----
<.> Mandatory - specifies the core of the Apache Causeway framework
<.> Enables the Shiro security mechanism.
There are several security implementations, precisely one must be selected
<.> Enables JPA/Eclipselink for persistence.
+
If using JDO as the ORM, replace with `CausewayModuleJdoDataNucleus5`.
<.> Enables the xref:vro:ROOT:about.adoc[REST API (Restful Objects viewer)] (ie REST API).
<.> Enables the xref:vw:ROOT:about.adoc[Web UI (Wicket viewer)]
<.> Enables the H2 Console (menu from the "Prototyping" menu), applicable only if running against h2 in-memory database.
<.> Brings in support to run xref:testing:fixtures:about.adoc[fixtures] within the application, eg for prototyping.
<.> Enables the xref:userguide:flyway:about.adoc[Flyway] integration.
<.> References the application's module(s), in this case `ApplicationModule` , `CustomModule` and `QuartzModule`.
+
`ApplicationModule` is discussed below.
<.> Makes the fixture scenario classes available for discovery.
<.> Normally configuration properties are picked up from Spring Boot's `application.properties` or `application.yml` files, but additional properties can be overridden directly.
These two both use the `CausewayPresets` convenience class, to disable i18n support and for additional debugging log statements.
==== SimpleApp
The application is bootstrapped using `SimpleApp`, a regular `@SpringBootApplication`.
It is mostly boilerplate:
[source,java]
----
@SpringBootApplication
@Import({
AppManifest.class, // <.>
})
public class SimpleApp
extends SpringBootServletInitializer {
public static void main(String[] args) {
CausewayPresets.prototyping(); // <.>
SpringApplication.run(
new Class[] { SimpleApp.class }, args);
}
}
----
<.> references the `AppManifest` mentioned earlier
<.> specifies prototyping mode.
This enables actions marked for prototyping to become available, useful during the early stages of development.
+
TIP: As an alternative to making this call, you can also just run with a system property `-DPROTOTYPING=true`
=== webapp's src/main/resources
Under `src/main/resources` we have:
[source]
----
src/main/resources
config/
application.properties <.>
application-SQLSERVER.properties <.>
application-POSTGRES.properties <.>
db/
migration/
SQLSERVER/
Vyyyy.mm.dd.hh.ss__xxx.sql <.>
static/ <.>
templates/ <.>
application.yml <.>
banner.txt <.>
log4j2-spring.xml <.>
menubars.layout.xml <.>
shiro.ini <.>
----
<.> By convention, we use `config/application.properties` to hold configuration properties that change between environments (dev, test, prod).
Typically this just holds JDBC connection strings, etc.
<.> Enabled if run using the `SQLSERVER` profile (eg using `-Dspring.profiles.active=SQLSERVER`). Configures to use a SQL Server database, and enables Flyway to set up the database schema
<.> Flyway migration scripts. +
This leverages a feature in Spring Boot's Flyway integration which allows different variants of scripts for different vendors to be stored, in a `+db.migration.{vendor}+` package.
<.> The `static` package (a link:https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-spring-mvc-static-content[Spring convention]) provides access for static resources that are accessible from the webapp
<.> The `templates` package holds a fallback error page, which is the link:https://www.baeldung.com/spring-thymeleaf-template-directory#change-default[default location] for pages rendered using Spring Boot's integration with Thymeleaf.
<.> By convention, we use `application.yml` to hold configuration properties that do _not_ change between environments.
<.> The `banner.txt` is shown when bootstrapping.
<.> The `log4j2-spring.xml` configures log4j2 (the logging system used by Apache Causeway)
<.> The `menubars.layout.xml` arranges the actions of the domain services into menus.
<.> The `shiro.ini` file configures Shiro security integration (see the `CausewayModuleSecurityShiro` module imported in the `AppManifest`, above).
+
[TIP]
====
The xref:security:shiro:about.adoc[Shiro security] integration is much more flexible than simple file-based authentication.
====
To call out some of the files under `static`:
* The `index.html` is the page shown at the root of the package, providing links to either the Wicket viewer or to the Swagger UI.
In a production application this is usually replaced with a page that does an HTTP 302 redirect to the Wicket viewer.
* In `css/application.css` you can use to customise CSS, typically to highlight certain fields or states.
The pages generated by the Wicket viewer have plenty of CSS classes to target.
You can also implement the `cssClass()` method in each domain object to provide additional CSS classes to target.
* Similarly, in `scripts/application.js` you have the option to add arbitrary JavaScript.
JQuery is available by default.
=== No src/main/webapp
Note that there is no `src/main/webapp/` or `WEB-INF/web.xml` - the servlets and filters are configured by Apache Causeway automatically.
[#integration-tests]
=== webapp-test's src/test/java
Under `src/test/java` we have a number of integration tests,
The integration tests are in `domainapp.application.integtests`:
[source]
----
src/
test/
java/
domainapp/
webapp/
integtests/
metamodel/
SwaggerExport_IntegTest.java <.>
ValidateDomainModel_IntegTest.java <.>
smoke/
Smoke_IntegTest.java <.>
ApplicationIntegTestAbstract.java <.>
----
<.> Exports the Swagger definition file.
+
This could then be used to automate generation of client stubs in various languages.
<.> Bootstraps the app and runs the metamodel validators to check that there are not metamodel errors.
+
This can also be done simply when running the application, but performing the checks through integration tests enables "fail-fast" checking, as part of CI, for example.
<.> Performs a number of high-level smoke tests, to check that the core functionality works correctly.
<.> Base class used to bootstrap all integration tests for this module.
It is very similar to the base class used to bootstrap the integration tests for the simple module xref:simpleapp.adoc#simplemoduleintegtestabstract[], but referencing `ApplicationModule` rather than `SimpleModule`.
[IMPORTANT]
====
The naming convention of tests classes is important, because the starter parent pom xref:parent-pom:about.adoc#surefire-configuration[configures the Maven surefire plugin] to execute multiple times, based on test class suffix.
The suffixes are: `Test` (unit tests, if any) and `IntegTest` (integ tests, if any).
// for 2.0.0-M6, change to:
//
// The suffixes are: `Test` (unit tests, if any), `IntegTest` (integ tests, if any) and `IntegBddSpecs` (BDD cucumber specs, if any) respectively.
====
=== Root module's pom.xml
In the parent module we of course have the `pom.xml`.
This inherits from `causeway-app-starter-parent`:
[source,xml]
.pom.xml
----
<parent>
<groupId>org.apache.causeway.app</groupId>
<artifactId>causeway-app-starter-parent</artifactId>
<version>XXX</version>
</parent>
----
\... which builds upon Spring Boot's own `org.springframework.boot:spring-boot-starter-parent`.
This means:
* the set of third party dependencies declared have been validated as compatible by Spring Boot team
* build plugins are declared and configured appropriately
* imports to the Apache Causeway dependencies are declared via `<dependencyManagement>`
== Running from within the IDE
Most of the time you'll probably want to run the app from within your IDE.
The mechanics of doing this will vary by IDE; see the xref:setupguide:ROOT:about.adoc[Setup Guide] for details.
Basically, though, it amounts to running the `main()` method in the `SimpleApp` class.
Here's what the setup looks like in IntelliJ IDEA:
image::simpleapp/simpleapp-webapp.png[width="600px"]
If using JDO as the ORM (rather than JPA), then the DataNucleus enhancer must be run beforehand.
With IntelliJ this can be done by setting up a different _Run Configuration_ to be executed beforehand:
image::simpleapp/simpleapp-webapp-before-launch.png[width="600px"]
== Experimenting with the App
Once you are familiar with the app, try modifying it.
There is plenty more guidance on this site; start with the xref:userguide:ROOT:about.adoc[User Guide Fundamentals] and then look at the other guides linked to from the top-level menu or from the main xref:docs:ROOT:about.adoc[table of contents].
If you run into issues, please don't hesitate to ask for help on the users mailing list or the Slack channel, as per the xref:docs:support:about.adoc[support page].
== Using an external database and FlywayDB
The application is configured by default uses H2 as an inmemory database, with <<fixtures,fixtures>> used to populate the database with representative data.
To deploy to production though of course will require a persistent database, and the schema of the tables will be explicitly managed.
Although both JDO and JPA can automatically create the database schema, many development teams choose to manage the schema externally to the ORM.
A popular tool to do this is link:https://flywaydb.org/[Flyway], and Spring Boot provides automatic support for it using link:https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#common-application-properties-data-migration[these configuration properties].
The simpleapp demonstrates how this can be done using SQL Server.
Adapt the following for your own preferred database.
=== Prereqs
If you happen to use SQL Server, then just use a dev instance.
Otherwise, you can easily run up an instance using Docker:
[source,bash]
----
docker run \
--name sqlserver \
-e 'ACCEPT_EULA=Y' \
-e 'SA_PASSWORD=pa$$w0rd' \
-p 1433:1433 \
-d mcr.microsoft.com/mssql/server:2019-latest
----
You can then connect:
* if on Linux/Mac, start a command line client using:
+
[source,bash]
----
docker exec -it sqlserver \
/opt/mssql-tools/bin/sqlcmd \
-S localhost -U sa -P pa$$w0rd
----
* if on Windows, you might instead prefer to use Microsoft's free GUI client, link:https://docs.microsoft.com/en-us/sql/ssms/download-sql-server-management-studio-ssms?view=sql-server-ver15[SQL Server Management Studio].
You then need to create a database and login:
[source,sql]
----
CREATE DATABASE [simpleapp]
go
CREATE LOGIN [simpleapp]
WITH PASSWORD=N'simpleapp',
DEFAULT_DATABASE=[simpleapp],
CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF
go
USE [simpleapp]
GO
ALTER AUTHORIZATION ON DATABASE::[simpleapp] TO [simpleapp]
GO
----
If using the command line, type 'exit' to quit out.
To confirm the connect, try logging in as simpleapp/simpleapp, and verify using:
[source,sql]
----
select db_name(), user_name()
go
----
This should return `simpleapp` and `dbo` respectively, meaning that the `simpleapp` login is all-powerful in the `simpleapp` database.
=== Enabling Flyway
With the backend database running, we can now run the simpleapp application with Flyway enabled.
This is done simply by activating the "SQLSERVER" profile (see also the link:https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-profiles[Spring docs]):
* either by setting a system property:
+
[source,bash]
----
-Dspring.profiles.active=SQLSERVER
----
* or by setting an environment variable:
+
[source,bash]
----
export SPRING_PROFILES_ACTIVE=SQLSERVER
----
This will cause Spring to read in the `config/application-SQLSERVER.properties` file:
[source,properties]
.config/application-SQLSERVER.properties
----
spring.flyway.enabled=true
spring.flyway.default-schema=SIMPLE
spring.flyway.schemas=SIMPLE
spring.sql.init.platform=sqlserver
spring.datasource.url=jdbc:sqlserver://localhost;databaseName=simpleapp
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.username=simpleapp
spring.datasource.password=simpleapp
#causeway.persistence.schema.create-schema-sql-template= (use flyway instead)
causeway.persistence.schema.auto-create-schemas=
# DataNucleus, and must use camelCase rather than kebab-case
datanucleus.schema.autoCreateAll=false
----
Flyway in turn reads the migration scripts under `db.migration` package (in `src/main/resources` of the `webapp` module).
Run up the application and Flyway will run in the scripts.
It will also create its own table, `SIMPLE.flyway_schema_history`:
image::simpleapp/flyway/tables-created.png[width=300px]
=== Cleaning up
If you were using Docker to try this out, remember to clean up afterwards:
[source,bash]
----
docker kill sqlserver
docker rm sqlserver
----