This is an automated email from the ASF dual-hosted git repository. danhaywood pushed a commit to branch CAUSEWAY-2873 in repository https://gitbox.apache.org/repos/asf/causeway.git
commit f51977f55ea0777094b5681ef7597e90f755ee78 Author: Dan Haywood <[email protected]> AuthorDate: Sun May 26 17:43:37 2024 +0100 CAUSEWAY-2873: 05-02 --- .../petclinic/images/05-02/Visit-entity.png | Bin 0 -> 14304 bytes .../modules/petclinic/pages/050-visit-entity.adoc | 233 +++++++++++++++++---- .../modules/petclinic/pages/100-todo.adoc | 3 + 3 files changed, 201 insertions(+), 35 deletions(-) diff --git a/antora/components/tutorials/modules/petclinic/images/05-02/Visit-entity.png b/antora/components/tutorials/modules/petclinic/images/05-02/Visit-entity.png new file mode 100644 index 0000000000..ea0c3a9ab9 Binary files /dev/null and b/antora/components/tutorials/modules/petclinic/images/05-02/Visit-entity.png differ diff --git a/antora/components/tutorials/modules/petclinic/pages/050-visit-entity.adoc b/antora/components/tutorials/modules/petclinic/pages/050-visit-entity.adoc index 05b25751be..ff93eec71c 100644 --- a/antora/components/tutorials/modules/petclinic/pages/050-visit-entity.adoc +++ b/antora/components/tutorials/modules/petclinic/pages/050-visit-entity.adoc @@ -75,64 +75,122 @@ causeway.persistence.schema.auto-create-schemas=\ ---- -== next exercise: +[#exercise-5-2-visit-module-dependencies] +== Ex 5.2: Visit Module Dependencies -set up dependencies -- maven -- spring -reference new module in AppManifest -- remove transitive dependencies +Although we have a visit module, it currently is unaware of the pet owner module. +And similarly, the top-level application doesn't yet know about visit module. +In this exercise we'll fix this, so that: + +application -> visit module -> petowner module + + + +=== Solution + +[source,bash] +---- +git checkout tags/05-02-visit-module-dependencies +mvn clean install +mvn -pl spring-boot:run +---- + +=== tasks + +* in the new visit module's `pom.xml`, add a Maven dependency on `petowner` module: ++ +[source,xml] +.visit/pom.xml +---- +<dependency> + <groupId>org.apache.causeway.starters</groupId> + <artifactId>simpleapp-jpa-module-petowner</artifactId> +</dependency> +---- ++ +TIP: In your IDE you may need to reload/refresh dependencies to rebuild the classpath. + +* in the `VisitModule` Causeway module, add a corresponding import on `PetOwnerModule`: + [source,java] -.VisitsModule.java +.VisitModule.java ---- +@Configuration +@Import({ + PetOwnerModule.class, + // ... +}) +// ... +public class VisitModule ... { ... } ---- +* in the webapp module, add a Maven dependency on the visit module: +[source,xml] +.visit/pom.xml +---- +<dependency> + <groupId>org.apache.causeway.starters</groupId> + <artifactId>simpleapp-jpa-module-visit</artifactId> +</dependency> +---- ++ +The dependency on `<artifactId>simpleapp-jpa-module-petowner</artifactId>` can also be removed, due to transitivity. + +* and in the webapp's `ApplicationModule` Causeway module, add a corresponding import on `VisitModule`. + [source,java] .ApplicationModule.java ---- +@Configuration +@Import({ + VisitModule.class, + SimpleModule.class, +}) +@ComponentScan +public class ApplicationModule { +} ---- ++ +The import on `PetOwnerModule.class` can be removed, due to transitivity. +Run the application and check that it starts ok. - -[#exercise-5-2-visit-entitys-key-properties] -== Ex 5.2: Visit entity's key properties +[#exercise-5-3-visit-entitys-key-properties] +== Ex 5.3: Visit entity's key properties Now we have a visits module, we can now add in the `Visit` entity. We'll start just with the key properties. +=== Solution [source,bash] ---- -git checkout tags/05-02-visit-entity-key-properties +git checkout tags/05-03-visit-entity-key-properties mvn clean install mvn -pl spring-boot:run ---- - === Tasks -* add a `Visit` entity, declaring the `pet` and `visitedAt` key properties: +* add a `Visit` entity (in the `dom.visit` subpackage), declaring the `pet` and `visitAt` key properties: + [source,java] .Visit.java ---- @Entity @Table( - schema="visits", // <.> - name = "Visit", - uniqueConstraints = { - @UniqueConstraint(name = "Visit__pet_visitAt__UNQ", columnNames = {"owner_id", "name"}) - } + schema=VisitModule.SCHEMA, + uniqueConstraints = { + @UniqueConstraint(name = "Visit__pet_visitAt__UNQ", columnNames = {"pet_id", "visitAt"}) + } ) @EntityListeners(CausewayEntityListener.class) -@Named("visits.Visit") +@Named(VisitModule.NAMESPACE + ".Visit") @DomainObject(entityChangePublishing = Publishing.ENABLED) @DomainObjectLayout() @NoArgsConstructor(access = AccessLevel.PUBLIC) @@ -144,7 +202,6 @@ public class Visit implements Comparable<Visit> { @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id", nullable = false) @Getter @Setter - @PropertyLayout(fieldSetId = "metadata", sequence = "1") private Long id; @Version @@ -153,26 +210,27 @@ public class Visit implements Comparable<Visit> { @Getter @Setter private long version; - Visit(Pet pet, LocalDateTime visitAt) { this.pet = pet; this.visitAt = visitAt; } - + @ObjectSupport public String title() { - return titleService.titleOf(getPet()) + " @ " + getVisitAt().format(DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm")); + return titleService.titleOf(getPet()) // <.> + + " @ " + + getVisitAt().format(DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm")); } @ManyToOne(optional = false) @JoinColumn(name = "pet_id") - @PropertyLayout(fieldSetId = "name", sequence = "1") + @PropertyLayout(fieldSetId = "identity", sequence = "1") @Getter @Setter private Pet pet; @Column(name = "visitAt", nullable = false) @Getter @Setter - @PropertyLayout(fieldSetId = "name", sequence = "2") + @PropertyLayout(fieldSetId = "identity", sequence = "2") private LocalDateTime visitAt; @@ -184,25 +242,134 @@ public class Visit implements Comparable<Visit> { return comparator.compare(this, other); } - @Inject @Transient TitleService titleService; + @Inject @Transient TitleService titleService; // <1> } ---- -<.> in the "visits" schema. -Modules are vertical, cutting through the layers. -Therefore the database schemas echo the Spring ``@Configuration``s and maven modules. +<.> uses the injected xref:refguide:applib:index/services/title/TitleService.adoc[] to obtain the title of the object, as determined by the framework. + +* create a `Visit.layout.xml` layout file: ++ +[source,xml] +.Visit.layout.xml +---- +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<bs3:grid + xsi:schemaLocation="https://causeway.apache.org/applib/layout/component https://causeway.apache.org/applib/layout/component/component.xsd https://causeway.apache.org/applib/layout/grid/bootstrap3 https://causeway.apache.org/applib/layout/grid/bootstrap3/bootstrap3.xsd" + xmlns:cpt="https://causeway.apache.org/applib/layout/component" + xmlns:bs3="https://causeway.apache.org/applib/layout/grid/bootstrap3" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <bs3:row> + <bs3:col span="12" unreferencedActions="true"> + <cpt:domainObject bookmarking="AS_ROOT"/> + </bs3:col> + </bs3:row> + <bs3:row> + <bs3:col span="6"> + <bs3:row> + <bs3:col span="12"> + <bs3:tabGroup> + <bs3:tab name="Identity"> + <bs3:row> + <bs3:col span="12"> + <cpt:fieldSet name="Identity" id="identity"/> + </bs3:col> + </bs3:row> + </bs3:tab> + <bs3:tab name="Other"> + <bs3:row> + <bs3:col span="12"> + <cpt:fieldSet name="Other" id="other" unreferencedProperties="true"/> + </bs3:col> + </bs3:row> + </bs3:tab> + <bs3:tab name="Metadata"> + <bs3:row> + <bs3:col span="12"> + <cpt:fieldSet name="Metadata" id="metadata"/> + </bs3:col> + </bs3:row> + </bs3:tab> + </bs3:tabGroup> + </bs3:col> + <bs3:col span="12"> + <cpt:fieldSet name="Details" id="details"/> + </bs3:col> + </bs3:row> + </bs3:col> + <bs3:col span="6"> + <bs3:row> + <bs3:col span="12"> + </bs3:col> + </bs3:row> + <bs3:tabGroup unreferencedCollections="true"> + </bs3:tabGroup> + </bs3:col> + </bs3:row> +</bs3:grid> +---- + +* create a `Visit.columnOrder.txt` file + -Run the application, and confirm that the table is created correctly using menu:Prototyping[H2 Console]. +[source,text] +.Visit.columnOrder.txt +---- +pet +visitAt +#id +#version +---- + +* download a `Visit.png` file. + +Run the application, and login as `secman-admin`/`pass` to confirm that the table is created correctly using menu:Prototyping[H2 Console]. +Also check that the unique index has been created correctly. + +image::05-02/Visit-entity.png[] + [#exercise-5-3-book-visit-action] == Ex 5.3: "Book Visit" action +We now want to extend our domain model so that ``Visit``s to be created. + +However, there's a problem: + +* we would like that behaviour to reside on `PetOwner` (say) +* however the pet owner module doesn't know about visits. + +We can see this in the domain model: + +include::partial$domain.adoc[] + +Causeway's solution to this is to allow the visit module to define behaviour, but have the behaviour seem to belong to the `Pet` entity, at least so far as the user interface is concerned. +This is done using a xref:userguide::mixins.adoc[]. + + +=== Solution + +[source,bash] +---- +git checkout tags/05-03-book-visit-action +mvn clean install +mvn -pl spring-boot:run +---- + + + +=== Tasks + + + +[#exercise-5-4-capture-visit-reason] +== Ex 5.3: Capture visit reason + In addition to the key properties, the `Visit` has one further mandatory property, `reason`. This is required to be specified when a `Visit` is created ("what is the purpose of this visit?") -In this exercise we'll add that additional property and use a mixin to allow ``Visit``s to be created. +In this exercise we'll extend the "book visit" action to also capture that reason. [source,bash] @@ -322,10 +489,6 @@ public class Pet_bookVisit { Also add in the UI files: -* create a `Visit.layout.xml` layout file. - -* add a `Visit.png` file - * add a `Pet#visits.columnOrder.txt` file + to define which properties of Visit are visible as columns in ``Pet``'s `visits` collection. diff --git a/antora/components/tutorials/modules/petclinic/pages/100-todo.adoc b/antora/components/tutorials/modules/petclinic/pages/100-todo.adoc index 25edb2f568..5ce9d43c8d 100644 --- a/antora/components/tutorials/modules/petclinic/pages/100-todo.adoc +++ b/antora/components/tutorials/modules/petclinic/pages/100-todo.adoc @@ -9,6 +9,9 @@ validate pet name is unique within Pet refactor addPet to be an inline-mixin. +update home page, show upcoming appointments + + visit - need some words about adding VisitRepository
