blob: b2c12f45af0ee98d848834ca01cbb45b798ae129 [file] [log] [blame]
= HelloWorld
: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 start learning about Apache Causeway is to use the `helloworld` starter app.
There are two variations of the application (and so two branches in the git repo).
One variation uses JDO as the ORM, the other uses JPA, 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-helloworld:v{fwk-version}-jpa-SNAPSHOT
----
Replace "v{fwk-version}-jpa" with "v{fwk-version}-jdo" if using the JDO ORM.
Using the instructions <<Downloading & Running,below>>, you can download a minimal Apache Causeway app, consisting of a single domain entity (`HelloWorldObject`) with supporting domain services.
Both the business logic and supporting bootstrapping classes are in a single Maven module.
[TIP]
====
We don't recommend that you use the helloworld starter app as the basis for your own applications.
Instead, use the xref:docs:starters:simpleapp.adoc[SimpleApp starter app].
It also creates a minimal application, but provides more structure along with tests, useful as you build out your own app.
====
== 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 helloworld app 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::helloworld-script-jdo.adoc[]
* if using JPA as the ORM:
+
include::helloworld-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::helloworld/using/010-root-page.png[width="600px"]
Choose the generic Wicket UI, and navigate to the login page:
image::helloworld/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::helloworld/using/030-home-page.png[width="600px"]
==== Create an object
The application is configured to run with an in-memory database, so initially there is no data.
Create an object using the menu:
image::helloworld/using/040-create-object-from-menu.png[width="600px"]
which brings up a modal dialog:
image::helloworld/using/050-create-object-from-menu-prompt.png[width="600px"]
hitting OK returns the created object:
image::helloworld/using/060-created-object.png[width="600px"]
The above functionality is implemented by this code (in the `HelloWorldObjects` menu domain service):
[source,java]
----
@Action(semantics = SemanticsOf.NON_IDEMPOTENT)
@ActionLayout(promptStyle = PromptStyle.DIALOG_MODAL)
public HelloWorldObject create(
@Name final String name) {
return repositoryService.persist(new HelloWorldObject(name));
}
public String default0Create() {
return "Hello World!";
}
----
==== Invoke an action
The `HelloWorldObject` 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::helloworld/using/070-update-name.png[width="600px"]
The above functionality is implemented by this code (in the `HelloWorldObject` entity):
[source,java]
----
@Action( semantics = SemanticsOf.IDEMPOTENT, executionPublishing = Publishing.ENABLED )
@ActionLayout(
associateWith = "name",
describedAs = "Updates the object's name"
)
public HelloWorldObject 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::helloworld/using/080-edit-notes.png[width="600px"]
==== Actions requiring confirmations
It's also possible to delete an object:
image::helloworld/using/090-delete-object.png[width="600px"]
The viewer should display a pop-up message confirming that the object has been deleted.
The above functionality is implemented by this code (in the `HelloWorldObject` entity):
[source,java]
----
@Action(semantics = SemanticsOf.NON_IDEMPOTENT_ARE_YOU_SURE)
@ActionLayout(position = ActionLayout.Position.PANEL)
public void delete() {
final String title = titleService.titleOf(this); // <.>
messageService.informUser(String.format("'%s' deleted", title));
repositoryService.removeAndFlush(this);
}
----
<.> Note that this method 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::helloworld/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::helloworld/using/210-helloworld-resources.png[width="600px"]
For example, an object can be created using the resource that represents the `HelloWorldObjects#create` action:
image::helloworld/using/220-create-object-thru-rest-api.png[width="600px"]
The response indicates that the object was successfully created:
image::helloworld/using/230-create-object-thru-rest-api-response.png[width="600px"]
The Swagger UI also provides a resource to retrieve any object:
image::helloworld/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::helloworld/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
The helloworld starter app consists of a single Maven module.
=== src/main/java
Under `src/main/java` we have:
[source]
----
src/main/java/
domainapp/ <!--.-->
modules
hello/ <!--.-->
dom/ <!--.-->
hwo/ <!--.-->
HelloWorldObject.java
HelloWorldObject.layout.xml
HelloWorldObject.png
HelloWorldObjectRepository.java <!--.-->
HelloWorldObjects.java
types/ <!--.-->
Name.java
Notes.java
HelloWorldModule.java <!--.-->
webapp/
AppManifest.java <!--.-->
HelloWorldApp.java <!--.-->
META-INF /
persistence.xml <!--.-->
----
<.> For simplicity, all the Java source files reside in a `domainapp` top-level package.
Change as required.
<.> Defines the 'hello' module.
Apache Causeway can be used for both microservice and monolithic architectures, but for the latter it encourages "modular monoliths" from the start.
<.> The `dom` package holds the "domain object model" for this module.
Modules may have other packages, common ones include ``types`` (as below), also ``api``s, ``contribution``s, ``fixture``s, ``spi``s
<.> Holds classes for the `hwo` ("hello world object") entity/aggregate, consisting of the entity definition itself (`HelloWorldObject`) and a corresponding repository (`HelloWorldObjects`).
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 `types` package contains meta-annotations to describe the usage of common value types such as ``String``s.
<.> `HelloWorldModule` 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 xref:#helloworldmodule[below].
<.> `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 `HelloWorldModule`). +
This is discussed in more detail xref:#appmanifest[below].
<.> `HelloWorldApp` 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`. +
This is discussed in more detail xref:#helloworldapp[below].
<.> For the `jdo` branch only, the `persistence.xml` file is required boilerplate.
[#helloworldmodule]
==== HelloWorldModule
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 `HelloWorldModule`, it is extremely simple:
[source,java]
.HelloWorldModule.java
----
package domainapp.modules.hello;
... imports omitted ...
@Configuration
@Import({}) // <.>
@ComponentScan // <.>
@EnableJpaRepositories // <.>
@EntityScan( // <.>
basePackageClasses = {
HelloWorldModule.class
})
public class HelloWorldModule {
}
----
<.> 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
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.
+
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 helloworld starter app, the main domain services is `HelloWorldObjects`.
This appears in the menu, and also acts as a repository for the `HelloWorldObject` entity.
The `jpa` branch also has the `HelloWorldRepository` 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 helloworld starter app, the only entity is `HelloWorldObject`.
* 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).
+
The helloworld starter app doesn't provide any examples of these.
[#appmanifest]
==== AppManifest
The "app manifest" is the top-level Spring `@Configuration`.
In the case of the helloworld starter app *for the `jdo` branch* the `AppManifest` looks like this:
[source,java]
.AppManifest.java
----
@Configuration
@Import({
CausewayModuleCoreRuntimeServices.class, // <.>
CausewayModuleSecurityShiro.class, // <.>
CausewayModuleJdoDataNucleus5.class, // <.>
CausewayModuleViewerRestfulObjectsJaxrsResteasy4.class, // <.>
CausewayModuleViewerWicketViewer.class, // <.>
CausewayModuleTestingH2ConsoleUi.class, // <.>
HelloWorldModule.class // <.>
})
@PropertySource(CausewayPresets.NoTranslations) // <.>
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 JDO/DataNucleus for persistence.
Optional (though if omitted then only xref:userguide:ROOT:view-models.adoc[view models] may be used, with hand-rolled persistence).
<.> 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.
<.> References the application's module(s), in this case just the one, `HelloWorldModule`.
<.> Normally configuration properties are picked up from Spring Boot's `application.properties` or `application.yml` files, but additional properties can be overridden directly.
This particular one disables the framework's i18n support using the `CausewayPresets` convenience class.
For the `jpa` branch the `AppManifest` is almost identical, just replacing:
* `CausewayModuleJdoDataNucleus5.class,`
with:
* `CausewayModuleJpaEclipseLink.class,`
This bootstraps the JPA as the ORM instead of JDO.
[#helloworldapp]
==== HelloWorldApp
The application is bootstrapped using `HelloWorldApp`, a regular `@SpringBootApplication`.
It is mostly boilerplate:
[source,java]
----
@SpringBootApplication
@Import({
AppManifest.class, // <.>
})
public class HelloWorldApp
extends SpringBootServletInitializer {
public static void main(String[] args) {
CausewayPresets.prototyping(); // <.>
SpringApplication.run(
new Class[] { HelloWorldApp.class }, args);
}
}
----
<.> references the `AppManifest` mentioned <<AppManifest,above>>.
<.> 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`
====
=== src/main/resources
Under `src/main/resources` we have:
[source,ini]
----
src/main/resources
config/
application.properties <!--.-->
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.
<.> 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.
=== No src/test/java
There are no tests in helloworld.
You will find tests in the xref:docs:starters:simpleapp.adoc[SimpleApp starter app].
=== pom.xml
Finally, at the root directory 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 of setting up Eclipse or IntelliJ IDEA.
Basically, though, it amounts to running the `main()` method in the `HelloWorldApp` class.
Here's what the setup looks like in IntelliJ IDEA:
image::helloworld/helloworld.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::helloworld/helloworld-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].
== Moving on
When you are ready to start working on your own app, we _don't_ recommend building on top of the helloworld app.
Instead, we suggest that you start with the xref:docs:starters:simpleapp.adoc[simpleapp starter app].
Although a little more complex, it provides more structure and example tests, all of which will help guide you as your application grows.