You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2021/09/30 08:16:28 UTC

[isis] branch ISIS-2873-petclinic updated: ISIS-2873: adds to tutorial

This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch ISIS-2873-petclinic
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/ISIS-2873-petclinic by this push:
     new abf6ec5  ISIS-2873: adds to tutorial
abf6ec5 is described below

commit abf6ec5864d9cc66f56f049032a50e3a51e90b56
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Thu Sep 30 09:14:20 2021 +0100

    ISIS-2873: adds to tutorial
---
 .../tutorials/modules/petclinic/nav.adoc           |  14 +-
 ...adoc => 030-fleshing-out-the-owner-entity.adoc} | 163 ++++++++++++---------
 .../petclinic/pages/030-removing-boilerplatex.adoc |  88 -----------
 .../hints-and-tips/transactions-and-errors.adoc    |   2 +-
 4 files changed, 104 insertions(+), 163 deletions(-)

diff --git a/antora/components/tutorials/modules/petclinic/nav.adoc b/antora/components/tutorials/modules/petclinic/nav.adoc
index ca64d9d..e69f132 100644
--- a/antora/components/tutorials/modules/petclinic/nav.adoc
+++ b/antora/components/tutorials/modules/petclinic/nav.adoc
@@ -12,13 +12,13 @@
 * xref:020-the-petclinic-domain.adoc[The PetClinic Domain]
 ** xref:020-the-petclinic-domain.adoc#exercise-2-1-refactor-simpleobject-to-petowner[image:hand.png[] *2.1*: Refactor `SimpleObject` to `PetOwner`]
 
-* xref:040-fleshing-out-the-owner-entity.adoc[Fleshing out the PetOwner entity]
-** xref:040-fleshing-out-the-owner-entity.adoc#_rework_code_owner_code_s_name_code_firstname_code_and_code_lastname_code[image:hand.png[] *070*: Rework Owner's name (firstName and lastName)]
-** xref:040-fleshing-out-the-owner-entity.adoc#_derived_name_property[image:hand.png[] *080*: Derived name property]
-** xref:040-fleshing-out-the-owner-entity.adoc#_digression_changing_the_app_name[image:hand.png[] *090*: Digression: Changing the App Name]
-** xref:040-fleshing-out-the-owner-entity.adoc#_changing_the_object_type_class_alias[image:hand.png[] *100*: Changing the "Object Type" Class Alias]
-** xref:040-fleshing-out-the-owner-entity.adoc#_add_other_properties_for_code_owner_code[image:hand.png[] *110*: Add other properties for Owner]
-** xref:040-fleshing-out-the-owner-entity.adoc#_using_specifications_to_encapsulate_business_rules[image:hand.png[] *120*: Using specifications to encapsulate business rules]
+* xref:030-fleshing-out-the-owner-entity.adoc[Fleshing out the PetOwner entity]
+** xref:030-fleshing-out-the-owner-entity.adoc#_rework_code_owner_code_s_name_code_firstname_code_and_code_lastname_code[image:hand.png[] *070*: Rework Owner's name (firstName and lastName)]
+** xref:030-fleshing-out-the-owner-entity.adoc#_derived_name_property[image:hand.png[] *080*: Derived name property]
+** xref:030-fleshing-out-the-owner-entity.adoc#_digression_changing_the_app_name[image:hand.png[] *090*: Digression: Changing the App Name]
+** xref:030-fleshing-out-the-owner-entity.adoc#_changing_the_object_type_class_alias[image:hand.png[] *100*: Changing the "Object Type" Class Alias]
+** xref:030-fleshing-out-the-owner-entity.adoc#_add_other_properties_for_code_owner_code[image:hand.png[] *110*: Add other properties for Owner]
+** xref:030-fleshing-out-the-owner-entity.adoc#_using_specifications_to_encapsulate_business_rules[image:hand.png[] *120*: Using specifications to encapsulate business rules]
 
 * xref:050-prototyping.adoc[Prototyping]
 ** xref:050-prototyping.adoc#_fixture_scripts_for_owner[image:hand.png[] *130*: Fixture Scripts (for Owner)]
diff --git a/antora/components/tutorials/modules/petclinic/pages/040-fleshing-out-the-owner-entity.adoc b/antora/components/tutorials/modules/petclinic/pages/030-fleshing-out-the-owner-entity.adoc
similarity index 77%
rename from antora/components/tutorials/modules/petclinic/pages/040-fleshing-out-the-owner-entity.adoc
rename to antora/components/tutorials/modules/petclinic/pages/030-fleshing-out-the-owner-entity.adoc
index e46104c..6f6c736 100644
--- a/antora/components/tutorials/modules/petclinic/pages/040-fleshing-out-the-owner-entity.adoc
+++ b/antora/components/tutorials/modules/petclinic/pages/030-fleshing-out-the-owner-entity.adoc
@@ -3,93 +3,135 @@
 :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 ag [...]
 
 
-== Rework ``Owner``'s name (`firstName` and `lastName`)
+== Exercise 3.1: Rename PetOwner's name property
 
 In the domain we are working on, `Owner` has a `firstName` and a `lastName` property, not a single `name` property.
-Let's update `Owner` accordingly.
+
+In this exercise, we'll rename ``PetOwner``'s `name` property to be `lastName`, and change the fixture script that sets up data to something more realistic.
+
 
 
 === Solution
 
 [source,bash]
 ----
-git checkout tags/070-rework-Owners-name-firstName-and-lastName
-mvn clean package jetty:run
+git checkout tags/03-01-renames-PetOwner-name-property
+mvn clean install
+mvn -pl spring-boot:run
 ----
 
-=== Exercise
+=== Tasks
 
-* rename property `Owner#name` -> `Owner#lastName`
-* add property `Owner#firstName`:
+Checkout the solution above and review the git history to see the changes that have already been made.
+These include:
+
+* property `PetOwner#name` -> `PetOwner#lastName` renamed
+* JPA mappings updated:
+** the corresponding JPQL named queries
+** the method names of `PetOwnerRepository`
 +
-[source,java]
-----
-@javax.jdo.annotations.Column(allowsNull = "false", length = 40)
-@Property
-@Getter @Setter
-private String firstName;
-----
+This is a Spring Data repository, which uses a link:https://www.baeldung.com/spring-data-derived-queries[naming convention] to infer the queries
+
+** uniqueness constraint for `PetOwner`
 
-* update the constructor:
+* the action method names of `PetOwners` domain service renamed
 +
-[source,java]
+This also requires updating the `menubars.layout.xml`, which references these action names.
+
+* updating the xref:refguide:applib:index/annotation/ActionLayout.adoc#associateWith[@ActionLayout] of the `updateName` and `delete` action methods in `PetOwner`
++
+In the UI, the buttons for these actions are located close to the renamed "lastName" property
+
+* renames `@Name` meta-annotation to `@LastName`.
++
+Meta-annotations are a useful way of eliminating duplication where the same value type appears in multiple locations, for example as both an entity property and in action parameters.
+
+Build and run the application to make sure it still runs fine.
+
+
+
+== Exercise 3.2: Add PetOwner's firstName property
+
+Now that `PetOwner` has a `lastName` property, let's also add a `firstName` property.
+We'll also update our fixture script (which sets up ``PetOwner``s) so that it is more descriptive.
+
+
+=== Solution
+
+[source,bash]
 ----
-public Owner(final String lastName, final String firstName) {
-    this.lastName = lastName;
-    this.firstName = firstName;
-}
+git checkout tags/03-02-adds-PetOwner-firstName-property
+mvn clean install
+mvn -pl spring-boot:run
 ----
 
-* remove `@Title` annotation from `lastName` property, and add a `title()` method to derive from both properties:
+=== Tasks
+
+* copy `@LastName` meta-annotation to create `@FirstName`:
 +
 [source,java]
 ----
-public String title() {
-    return getLastName() + ", " + getFirstName().substring(0,1);
+@Property(maxLength = FirstName.MAX_LEN, optionality = Optionality.OPTIONAL)
+@Parameter(maxLength = FirstName.MAX_LEN, optionality = Optionality.OPTIONAL)
+@ParameterLayout(named = "First Name")
+@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface FirstName {
+
+    int MAX_LEN = 40;
 }
 ----
++
+Note that this property/parameter is optional.
+Its parameter name has also been updated.
 
 
-* update `Owner.layout.xml`
+* add a new (JPA nullable) property `firstName` to `PetOwner`:
 +
-[source,xml]
+[source,java]
 ----
-<c:property id="lastName" namedEscaped="true"/>
-<c:property id="firstName" namedEscaped="true">
-    <c:action id="updateName">
-        <c:describedAs>Updates the object's name</c:describedAs>
-    </c:action>
-</c:property>
+@FirstName
+@Column(length = FirstName.MAX_LEN, nullable = true)
+@Getter @Setter @ToString.Include
+@PropertyLayout(fieldSetId = "name", sequence = "2")
+private String firstName;
 ----
-+
-This will place the button for `updateName` underneath the `firstName` property.
 
-* update the corresponding JDO `@Unique` annotation for `Owner`:
+* add a new factory method to accept a `firstName`, and refactor the existing one:
 +
 [source,java]
 ----
-@javax.jdo.annotations.Unique(name="Owner_lastName_firstName_UNQ", members = {"lastName", "firstName"})
+public static PetOwner withName(String name) {
+    return withName(name, null);
+}
+
+public static PetOwner withName(String lastName, String firstName) {
+    val simpleObject = new PetOwner();
+    simpleObject.setLastName(lastName);
+    simpleObject.setFirstName(firstName);
+    return simpleObject;
+}
 ----
 
-* update the implementation of `Comparable` for `Owner`:
+
+* remove `@Title` annotation from `lastName` property, and add a `title()` method to derive from both properties:
 +
 [source,java]
 ----
-@Override
-public int compareTo(final Owner other) {
-    return ComparisonChain.start()
-            .compare(this.getLastName(), other.getLastName())
-            .compare(this.getFirstName(), other.getFirstName())
-            .result();
+public String title() {
+    return getLastName() + (getFirstName() != null ? ", " + getFirstName() : "");
 }
 ----
+
+
+* Update the `PetOwner_persona` enum with more realistically last names (family names).
 +
-[NOTE]
-====
-The archetype includes a dependency on guava, which is where `ComparisonChain` comes from.
-====
+Learn more about fixture scripts xref:testing:fixtures:about.adoc[here].
 
 
+
+== Exercise 3.3: Modify PetOwner's updateName action
+
 * update `Owner#updateName` to also accept a new `firstName` parameter:
 +
 [source,java]
@@ -130,28 +172,15 @@ public Owner create(
 }
 ----
 
-* update `Orders#findByName` to search across either the `firstName` or the `lastName`:
-+
-[source,java]
-----
-@Action(semantics = SemanticsOf.SAFE)
-@MemberOrder(sequence = "2")
-public List<Owner> findByName(
-        final String name) {
-    TypesafeQuery<Owner> q = isisJdoSupport.newTypesafeQuery(Owner.class);
-    final QOwner cand = QOwner.candidate();
-    q = q.filter(
-            cand.lastName.indexOf(q.stringParameter("name")).ne(-1).or(
-            cand.firstName.indexOf(q.stringParameter("name")).ne(-1)
-            )
-    );
-    return q.setParameter("name", name)
-            .executeList();
-}
-----
 
-* update test class `OwnerTest_updateName`
-* update test class `OwnerTest_delete`
+
+=== Optional exercises
+
+It would be nice if the `PetOwner` were identified by both their `firstName` and their `lastName`; at the moment every `PetOwner` must have a unique `lastName`.
+Or, even better would be to introduce some sort of "customerNumber" and use this as the unique identifier.
+
+
+
 
 
 
diff --git a/antora/components/tutorials/modules/petclinic/pages/030-removing-boilerplatex.adoc b/antora/components/tutorials/modules/petclinic/pages/030-removing-boilerplatex.adoc
deleted file mode 100644
index 764a35b..0000000
--- a/antora/components/tutorials/modules/petclinic/pages/030-removing-boilerplatex.adoc
+++ /dev/null
@@ -1,88 +0,0 @@
-== Removing boilerplate (Lombok)
-
-: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 ag [...]
-
-Java has a -- probably deserved -- reputation for being somewhat prone to boilerplate, obscuring the meaning of our code.
-There are however a couple of techniques we can use to reduce the boilerplate load.
-
-One of the most common areas of boilerplate is the getters and setters.
-We can use project lombok to remove the necessity of writing these methods.
-
-=== Solution
-
-[source,bash]
-----
-git checkout tags/030-removing-boilerplate-lombok
-mvn clean package jetty:run
-----
-
-=== Exercise
-
-* in the `pom.xml`, add the following to `<dependencies>`:
-+
-[source,xml]
-----
-<dependency>
-    <groupId>org.projectlombok</groupId>
-    <artifactId>lombok</artifactId>
-    <version>1.16.18</version>
-    <scope>provided</scope>
-</dependency>
-----
-
-* remove the getters and setters for `Owner#name` and add in its `@lombok.Getter` and `@lombok.Setter` annotations for its field instead:
-
-+
-[source,java]
-----
-@javax.jdo.annotations.Column(allowsNull = "false", length = 40)
-@Property(editing = Editing.DISABLED)
-@Title(prepend = "Object: ")
-@Getter @Setter                 // <1>
-private String name;
-----
-<1> added in, `getName()` and `setName()` removed
-
-* do likewise for the `Owner#notes` property
-
-
-== Removing boilerplate (Parameter names)
-
-Apache Isis uses Java reflection to infer the names of domain object types and members.
-However, prior to Java 8 the name of method parameters was not accessible, and thus an annotation is required to provide this information.
-
-For example, the `Owners#findByName(...)` action is:
-
-[source,java]
-----
-public class Owners {
-
-    @Action(semantics = SemanticsOf.NON_IDEMPOTENT)
-    @MemberOrder(sequence = "1")
-    public Owner create(
-            @Parameter(maxLength = 40)
-            @ParameterLayout(named = "Name")
-            final String name) {
-        return repositoryService.persist(new Owner(name));
-    }
-    ...
-}
-----
-
-The boilerplate here is the `@ParameterLayout#named` annotation.
-
-Given we're running on Java 8, though, we can remove this boilerplate.
-We do so by configuring the framework to also check for Java 8 metadata.
-
-
-=== Solution
-
-[source,bash]
-----
-git checkout tags/040-removing-boilerplate--Paraname8
-mvn clean package jetty:run
-----
-
-
-
-
diff --git a/antora/components/userguide/modules/btb/pages/hints-and-tips/transactions-and-errors.adoc b/antora/components/userguide/modules/btb/pages/hints-and-tips/transactions-and-errors.adoc
index 5087bd6..2912dc7 100644
--- a/antora/components/userguide/modules/btb/pages/hints-and-tips/transactions-and-errors.adoc
+++ b/antora/components/userguide/modules/btb/pages/hints-and-tips/transactions-and-errors.adoc
@@ -17,7 +17,7 @@ For example:
 
 [source,java]
 ----
-public class SomeLongRunningFixtureScript extends FixtureScript
+public class SomeLongRunningFixtureScript extends FixtureScript {
 
     protected void execute(final ExecutionContext executionContext) {
         // do some work