You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by da...@apache.org on 2024/05/22 08:59:07 UTC
(causeway-app-petclinic) 03/12: copies simple module to petowner module
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a commit to branch v2
in repository https://gitbox.apache.org/repos/asf/causeway-app-petclinic.git
commit 1f1fd0bcfd75d3fa057165581571031270141ec8
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Tue May 21 06:33:41 2024 +0100
copies simple module to petowner module
---
README.adoc | 3 +
.../domainapp/modules/petowner/PetOwnerModule.java | 43 ++++
.../petowner/dom/petowner/PetOwner.columnOrder.txt | 3 +
.../modules/petowner/dom/petowner/PetOwner.java | 235 +++++++++++++++++++++
.../petowner/dom/petowner/PetOwner.layout.xml | 55 +++++
.../modules/petowner/dom/petowner/PetOwner.png | Bin 0 -> 653 bytes
.../petowner/dom/petowner/PetOwnerRepository.java | 13 ++
.../modules/petowner/dom/petowner/PetOwners.java | 89 ++++++++
.../modules/petowner/fixture/PetOwner_persona.java | 108 ++++++++++
.../domainapp/modules/petowner/types/Name.java | 20 ++
.../domainapp/modules/petowner/types/Notes.java | 25 +++
.../domainapp/modules/petowner/fixture/Bang.docx | Bin 0 -> 13071 bytes
.../domainapp/modules/petowner/fixture/Bang.pdf | Bin 0 -> 48548 bytes
.../domainapp/modules/petowner/fixture/Bar.docx | Bin 0 -> 12936 bytes
.../domainapp/modules/petowner/fixture/Bar.pdf | Bin 0 -> 47488 bytes
.../domainapp/modules/petowner/fixture/Fizz.docx | Bin 0 -> 12869 bytes
.../domainapp/modules/petowner/fixture/Fizz.pdf | Bin 0 -> 46833 bytes
.../domainapp/modules/petowner/fixture/Foo.docx | Bin 0 -> 13069 bytes
.../domainapp/modules/petowner/fixture/Foo.pdf | Bin 0 -> 47185 bytes
.../domainapp/modules/petowner/fixture/Frodo.docx | Bin 0 -> 12969 bytes
.../domainapp/modules/petowner/fixture/Frodo.pdf | Bin 0 -> 47587 bytes
21 files changed, 594 insertions(+)
diff --git a/README.adoc b/README.adoc
index 2378fd1..3a221be 100644
--- a/README.adoc
+++ b/README.adoc
@@ -105,6 +105,9 @@ The following table explains the contents of each of the directories:
|Directory
|Description
+|`module-petowner`
+|Holds the "petowner" module, consisting of the `PetOwner` entity and supporting services.
+
|`module-simple`
|Holds the "simple" module, consisting of the `SimpleObject` entity and supporting services.
diff --git a/module-petowner/src/main/java/domainapp/modules/petowner/PetOwnerModule.java b/module-petowner/src/main/java/domainapp/modules/petowner/PetOwnerModule.java
new file mode 100644
index 0000000..7013f76
--- /dev/null
+++ b/module-petowner/src/main/java/domainapp/modules/petowner/PetOwnerModule.java
@@ -0,0 +1,43 @@
+package domainapp.modules.petowner;
+
+import org.springframework.boot.autoconfigure.domain.EntityScan;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+
+import org.apache.causeway.extensions.fullcalendar.applib.CausewayModuleExtFullCalendarApplib;
+import org.apache.causeway.extensions.pdfjs.applib.CausewayModuleExtPdfjsApplib;
+import org.apache.causeway.persistence.jpa.applib.CausewayModulePersistenceJpaApplib;
+import org.apache.causeway.testing.fakedata.applib.CausewayModuleTestingFakeDataApplib;
+import org.apache.causeway.testing.fixtures.applib.fixturescripts.FixtureScript;
+import org.apache.causeway.testing.fixtures.applib.modules.ModuleWithFixtures;
+import org.apache.causeway.testing.fixtures.applib.teardown.jpa.TeardownFixtureJpaAbstract;
+
+import domainapp.modules.petowner.dom.petowner.PetOwner;
+
+@Configuration
+@Import({
+ CausewayModuleExtPdfjsApplib.class,
+ CausewayModuleExtFullCalendarApplib.class,
+ CausewayModuleTestingFakeDataApplib.class,
+ CausewayModulePersistenceJpaApplib.class,
+})
+@ComponentScan
+@EnableJpaRepositories
+@EntityScan(basePackageClasses = {PetOwnerModule.class})
+public class PetOwnerModule implements ModuleWithFixtures {
+
+ public static final String NAMESPACE = "simple";
+ public static final String SCHEMA = "simple";
+
+ @Override
+ public FixtureScript getTeardownFixture() {
+ return new TeardownFixtureJpaAbstract() {
+ @Override
+ protected void execute(ExecutionContext executionContext) {
+ deleteFrom(PetOwner.class);
+ }
+ };
+ }
+}
diff --git a/module-petowner/src/main/java/domainapp/modules/petowner/dom/petowner/PetOwner.columnOrder.txt b/module-petowner/src/main/java/domainapp/modules/petowner/dom/petowner/PetOwner.columnOrder.txt
new file mode 100644
index 0000000..5f3107a
--- /dev/null
+++ b/module-petowner/src/main/java/domainapp/modules/petowner/dom/petowner/PetOwner.columnOrder.txt
@@ -0,0 +1,3 @@
+name
+lastCheckedIn
+#version
diff --git a/module-petowner/src/main/java/domainapp/modules/petowner/dom/petowner/PetOwner.java b/module-petowner/src/main/java/domainapp/modules/petowner/dom/petowner/PetOwner.java
new file mode 100644
index 0000000..7fb69a8
--- /dev/null
+++ b/module-petowner/src/main/java/domainapp/modules/petowner/dom/petowner/PetOwner.java
@@ -0,0 +1,235 @@
+package domainapp.modules.petowner.dom.petowner;
+
+import java.time.LocalTime;
+import java.time.ZoneOffset;
+import java.util.Comparator;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+import javax.persistence.UniqueConstraint;
+import javax.persistence.Version;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import org.springframework.lang.Nullable;
+
+import org.apache.causeway.applib.annotation.Action;
+import org.apache.causeway.applib.annotation.ActionLayout;
+import org.apache.causeway.applib.annotation.BookmarkPolicy;
+import org.apache.causeway.applib.annotation.DomainObject;
+import org.apache.causeway.applib.annotation.DomainObjectLayout;
+import org.apache.causeway.applib.annotation.Editing;
+import org.apache.causeway.applib.annotation.MemberSupport;
+import org.apache.causeway.applib.annotation.Optionality;
+import org.apache.causeway.applib.annotation.PromptStyle;
+import org.apache.causeway.applib.annotation.Property;
+import org.apache.causeway.applib.annotation.PropertyLayout;
+import org.apache.causeway.applib.annotation.Publishing;
+import org.apache.causeway.applib.annotation.TableDecorator;
+import org.apache.causeway.applib.annotation.Title;
+import org.apache.causeway.applib.jaxb.PersistentEntityAdapter;
+import org.apache.causeway.applib.layout.LayoutConstants;
+import org.apache.causeway.applib.services.message.MessageService;
+import org.apache.causeway.applib.services.repository.RepositoryService;
+import org.apache.causeway.applib.services.title.TitleService;
+import org.apache.causeway.applib.value.Blob;
+import org.apache.causeway.extensions.fullcalendar.applib.CalendarEventable;
+import org.apache.causeway.extensions.fullcalendar.applib.value.CalendarEvent;
+import org.apache.causeway.extensions.pdfjs.applib.annotations.PdfJsViewer;
+import org.apache.causeway.persistence.jpa.applib.integration.CausewayEntityListener;
+import org.apache.causeway.persistence.jpa.applib.types.BlobJpaEmbeddable;
+
+import static org.apache.causeway.applib.annotation.SemanticsOf.IDEMPOTENT;
+import static org.apache.causeway.applib.annotation.SemanticsOf.NON_IDEMPOTENT_ARE_YOU_SURE;
+
+import domainapp.modules.petowner.PetOwnerModule;
+import domainapp.modules.petowner.types.Name;
+import domainapp.modules.petowner.types.Notes;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.ToString;
+import lombok.val;
+
+
+@Entity
+@Table(
+ schema= PetOwnerModule.SCHEMA,
+ uniqueConstraints = {
+ @UniqueConstraint(name = "PetOwner__name__UNQ", columnNames = {"name"})
+ }
+)
+@NamedQueries({
+ @NamedQuery(
+ name = PetOwner.NAMED_QUERY__FIND_BY_NAME_LIKE,
+ query = "SELECT so " +
+ "FROM PetOwner so " +
+ "WHERE so.name LIKE :name"
+ )
+})
+@EntityListeners(CausewayEntityListener.class)
+@Named(PetOwnerModule.NAMESPACE + ".PetOwner")
+@DomainObject(entityChangePublishing = Publishing.ENABLED)
+@DomainObjectLayout(
+ tableDecorator = TableDecorator.DatatablesNet.class,
+ bookmarking = BookmarkPolicy.AS_ROOT)
+@NoArgsConstructor(access = AccessLevel.PUBLIC)
+@XmlJavaTypeAdapter(PersistentEntityAdapter.class)
+@ToString(onlyExplicitlyIncluded = true)
+public class PetOwner implements Comparable<PetOwner>, CalendarEventable {
+
+ static final String NAMED_QUERY__FIND_BY_NAME_LIKE = "PetOwner.findByNameLike";
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ @Column(name = "id", nullable = false)
+ private Long id;
+
+ @Version
+ @Column(name = "version", nullable = false)
+ @PropertyLayout(fieldSetId = "metadata", sequence = "999")
+ @Getter @Setter
+ private long version;
+
+ public static PetOwner withName(final String name) {
+ val PetOwner = new PetOwner();
+ PetOwner.setName(name);
+ return PetOwner;
+ }
+
+ @Inject @Transient RepositoryService repositoryService;
+ @Inject @Transient TitleService titleService;
+ @Inject @Transient MessageService messageService;
+
+
+
+ @Title
+ @Name
+ @Column(length = Name.MAX_LEN, nullable = false, name = "name")
+ @Getter @Setter @ToString.Include
+ @PropertyLayout(fieldSetId = LayoutConstants.FieldSetId.IDENTITY, sequence = "1")
+ private String name;
+
+ @Notes
+ @Column(length = Notes.MAX_LEN, nullable = true)
+ @Getter @Setter
+ @Property(commandPublishing = Publishing.ENABLED, executionPublishing = Publishing.ENABLED)
+ @PropertyLayout(fieldSetId = LayoutConstants.FieldSetId.DETAILS, sequence = "2")
+ private String notes;
+
+ @AttributeOverrides({
+ @AttributeOverride(name="name", column=@Column(name="attachment_name")),
+ @AttributeOverride(name="mimeType",column=@Column(name="attachment_mimeType")),
+ @AttributeOverride(name="bytes", column=@Column(name="attachment_bytes"))
+ })
+ @Embedded
+ private BlobJpaEmbeddable attachment;
+
+ @PdfJsViewer
+ @Property(optionality = Optionality.OPTIONAL)
+ @PropertyLayout(fieldSetId = "content", sequence = "1")
+ public Blob getAttachment() {
+ return BlobJpaEmbeddable.toBlob(attachment);
+ }
+ public void setAttachment(final Blob attachment) {
+ this.attachment = BlobJpaEmbeddable.fromBlob(attachment);
+ }
+
+
+
+ @Property(optionality = Optionality.OPTIONAL, editing = Editing.ENABLED)
+ @PropertyLayout(fieldSetId = LayoutConstants.FieldSetId.DETAILS, sequence = "3")
+ @Column(nullable = true)
+ @Getter @Setter
+ private java.time.LocalDate lastCheckedIn;
+
+
+ @Override
+ public String getCalendarName() {
+ return "Last checked-in";
+ }
+
+ @Override
+ public CalendarEvent toCalendarEvent() {
+ if (getLastCheckedIn() != null) {
+ long epochMillis = getLastCheckedIn().toEpochSecond(LocalTime.MIDNIGHT, ZoneOffset.systemDefault().getRules().getOffset(getLastCheckedIn().atStartOfDay())) * 1000L;
+ return new CalendarEvent(epochMillis, getCalendarName(), titleService.titleOf(this), getNotes());
+ } else {
+ return null;
+ }
+ }
+
+
+ @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 PetOwner updateName(
+ @Name final String name) {
+ setName(name);
+ return this;
+ }
+ @MemberSupport public String default0UpdateName() {
+ return getName();
+ }
+ @MemberSupport public String validate0UpdateName(final String newName) {
+ for (char prohibitedCharacter : PROHIBITED_CHARACTERS.toCharArray()) {
+ if( newName.contains(""+prohibitedCharacter)) {
+ return "Character '" + prohibitedCharacter + "' is not allowed.";
+ }
+ }
+ return null;
+ }
+ static final String PROHIBITED_CHARACTERS = "&%$!";
+
+
+
+ @Action(semantics = IDEMPOTENT, commandPublishing = Publishing.ENABLED, executionPublishing = Publishing.ENABLED)
+ @ActionLayout(associateWith = "attachment", position = ActionLayout.Position.PANEL)
+ public PetOwner updateAttachment(
+ @Nullable final Blob attachment) {
+ setAttachment(attachment);
+ return this;
+ }
+ @MemberSupport public Blob default0UpdateAttachment() {
+ return getAttachment();
+ }
+
+
+
+ @Action(semantics = NON_IDEMPOTENT_ARE_YOU_SURE)
+ @ActionLayout(
+ fieldSetId = LayoutConstants.FieldSetId.IDENTITY,
+ position = ActionLayout.Position.PANEL,
+ describedAs = "Deletes this object from the persistent datastore")
+ public void delete() {
+ final String title = titleService.titleOf(this);
+ messageService.informUser(String.format("'%s' deleted", title));
+ repositoryService.removeAndFlush(this);
+ }
+
+
+
+ private final static Comparator<PetOwner> comparator =
+ Comparator.comparing(PetOwner::getName);
+
+ @Override
+ public int compareTo(final PetOwner other) {
+ return comparator.compare(this, other);
+ }
+
+}
diff --git a/module-petowner/src/main/java/domainapp/modules/petowner/dom/petowner/PetOwner.layout.xml b/module-petowner/src/main/java/domainapp/modules/petowner/dom/petowner/PetOwner.layout.xml
new file mode 100644
index 0000000..6a393d4
--- /dev/null
+++ b/module-petowner/src/main/java/domainapp/modules/petowner/dom/petowner/PetOwner.layout.xml
@@ -0,0 +1,55 @@
+<?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">
+ <cpt:fieldSet name="Content" id="content"/>
+ </bs3:col>
+ </bs3:row>
+ <bs3:tabGroup unreferencedCollections="true">
+ </bs3:tabGroup>
+ </bs3:col>
+ </bs3:row>
+</bs3:grid>
diff --git a/module-petowner/src/main/java/domainapp/modules/petowner/dom/petowner/PetOwner.png b/module-petowner/src/main/java/domainapp/modules/petowner/dom/petowner/PetOwner.png
new file mode 100644
index 0000000..0bd6f57
Binary files /dev/null and b/module-petowner/src/main/java/domainapp/modules/petowner/dom/petowner/PetOwner.png differ
diff --git a/module-petowner/src/main/java/domainapp/modules/petowner/dom/petowner/PetOwnerRepository.java b/module-petowner/src/main/java/domainapp/modules/petowner/dom/petowner/PetOwnerRepository.java
new file mode 100644
index 0000000..2e301fd
--- /dev/null
+++ b/module-petowner/src/main/java/domainapp/modules/petowner/dom/petowner/PetOwnerRepository.java
@@ -0,0 +1,13 @@
+package domainapp.modules.petowner.dom.petowner;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface PetOwnerRepository extends JpaRepository<PetOwner, Long> {
+
+ List<PetOwner> findByNameContaining(final String name);
+
+ PetOwner findByName(final String name);
+
+}
diff --git a/module-petowner/src/main/java/domainapp/modules/petowner/dom/petowner/PetOwners.java b/module-petowner/src/main/java/domainapp/modules/petowner/dom/petowner/PetOwners.java
new file mode 100644
index 0000000..38fbb47
--- /dev/null
+++ b/module-petowner/src/main/java/domainapp/modules/petowner/dom/petowner/PetOwners.java
@@ -0,0 +1,89 @@
+package domainapp.modules.petowner.dom.petowner;
+
+import java.util.List;
+
+import javax.annotation.Priority;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.persistence.TypedQuery;
+
+import org.apache.causeway.applib.annotation.Action;
+import org.apache.causeway.applib.annotation.ActionLayout;
+import org.apache.causeway.applib.annotation.DomainService;
+import org.apache.causeway.applib.annotation.PriorityPrecedence;
+import org.apache.causeway.applib.annotation.PromptStyle;
+import org.apache.causeway.applib.annotation.SemanticsOf;
+import org.apache.causeway.applib.query.Query;
+import org.apache.causeway.applib.services.repository.RepositoryService;
+import org.apache.causeway.persistence.jpa.applib.services.JpaSupportService;
+
+import lombok.RequiredArgsConstructor;
+
+import domainapp.modules.petowner.PetOwnerModule;
+import domainapp.modules.petowner.types.Name;
+
+@Named(PetOwnerModule.NAMESPACE + ".PetOwners")
+@DomainService
+@Priority(PriorityPrecedence.EARLY)
+@RequiredArgsConstructor(onConstructor_ = {@Inject} )
+public class PetOwners {
+
+ final RepositoryService repositoryService;
+ final JpaSupportService jpaSupportService;
+ final PetOwnerRepository petOwnerRepository;
+
+
+ @Action(semantics = SemanticsOf.NON_IDEMPOTENT)
+ @ActionLayout(promptStyle = PromptStyle.DIALOG_SIDEBAR)
+ public PetOwner create(
+ @Name final String name) {
+ return repositoryService.persist(PetOwner.withName(name));
+ }
+
+
+ @Action(semantics = SemanticsOf.NON_IDEMPOTENT)
+ @ActionLayout(promptStyle = PromptStyle.DIALOG_SIDEBAR)
+ public List<PetOwner> findByNameLike(
+ @Name final String name) {
+ return repositoryService.allMatches(
+ Query.named(PetOwner.class, PetOwner.NAMED_QUERY__FIND_BY_NAME_LIKE)
+ .withParameter("name", "%" + name + "%"));
+ }
+
+
+ @Action(semantics = SemanticsOf.SAFE)
+ @ActionLayout(promptStyle = PromptStyle.DIALOG_SIDEBAR)
+ public List<PetOwner> findByName(
+ @Name final String name
+ ) {
+ return petOwnerRepository.findByNameContaining(name);
+ }
+
+
+ public PetOwner findByNameExact(final String name) {
+ return petOwnerRepository.findByName(name);
+ }
+
+
+
+ @Action(semantics = SemanticsOf.SAFE)
+ public List<PetOwner> listAll() {
+ return petOwnerRepository.findAll();
+ }
+
+
+
+ public void ping() {
+ jpaSupportService.getEntityManager(PetOwner.class)
+ .mapEmptyToFailure()
+ .mapSuccessAsNullable(entityManager -> {
+ final TypedQuery<PetOwner> q = entityManager.createQuery(
+ "SELECT p FROM PetOwner p ORDER BY p.name",
+ PetOwner.class)
+ .setMaxResults(1);
+ return q.getResultList();
+ })
+ .ifFailureFail();
+ }
+
+}
diff --git a/module-petowner/src/main/java/domainapp/modules/petowner/fixture/PetOwner_persona.java b/module-petowner/src/main/java/domainapp/modules/petowner/fixture/PetOwner_persona.java
new file mode 100644
index 0000000..20fc853
--- /dev/null
+++ b/module-petowner/src/main/java/domainapp/modules/petowner/fixture/PetOwner_persona.java
@@ -0,0 +1,108 @@
+package domainapp.modules.petowner.fixture;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import javax.inject.Inject;
+
+import org.springframework.core.io.ClassPathResource;
+
+import org.apache.causeway.applib.services.clock.ClockService;
+import org.apache.causeway.applib.services.registry.ServiceRegistry;
+import org.apache.causeway.applib.value.Blob;
+import org.apache.causeway.testing.fakedata.applib.services.FakeDataService;
+import org.apache.causeway.testing.fixtures.applib.personas.BuilderScriptWithResult;
+import org.apache.causeway.testing.fixtures.applib.personas.Persona;
+import org.apache.causeway.testing.fixtures.applib.setup.PersonaEnumPersistAll;
+
+import domainapp.modules.petowner.dom.petowner.PetOwners;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import lombok.SneakyThrows;
+import lombok.val;
+import lombok.experimental.Accessors;
+
+import domainapp.modules.petowner.dom.petowner.PetOwner;
+
+@RequiredArgsConstructor
+public enum PetOwner_persona
+implements Persona<PetOwner, PetOwner_persona.Builder> {
+
+ FOO("Foo", "Foo.pdf"),
+ BAR("Bar", "Bar.pdf"),
+ BAZ("Baz", null),
+ FRODO("Frodo", "Frodo.pdf"),
+ FROYO("Froyo", null),
+ FIZZ("Fizz", "Fizz.pdf"),
+ BIP("Bip", null),
+ BOP("Bop", null),
+ BANG("Bang", "Bang.pdf"),
+ BOO("Boo", null);
+
+ private final String name;
+ private final String contentFileName;
+
+ @Override
+ public Builder builder() {
+ return new Builder().setPersona(this);
+ }
+
+ @Override
+ public PetOwner findUsing(final ServiceRegistry serviceRegistry) {
+ return serviceRegistry.lookupService(PetOwners.class).map(x -> x.findByNameExact(name)).orElseThrow();
+ }
+
+ @Accessors(chain = true)
+ public static class Builder extends BuilderScriptWithResult<PetOwner> {
+
+ @Getter @Setter private PetOwner_persona persona;
+
+ @Override
+ protected PetOwner buildResult(final ExecutionContext ec) {
+
+ val PetOwner = wrap(PetOwners).create(persona.name);
+
+ if (persona.contentFileName != null) {
+ val bytes = toBytes(persona.contentFileName);
+ val attachment = new Blob(persona.contentFileName, "application/pdf", bytes);
+ PetOwner.updateAttachment(attachment);
+ }
+
+ PetOwner.setLastCheckedIn(clockService.getClock().nowAsLocalDate().plusDays(fakeDataService.ints().between(-10, +10)));
+
+ return PetOwner;
+ }
+
+ @SneakyThrows
+ private byte[] toBytes(String fileName){
+ InputStream inputStream = new ClassPathResource(fileName, getClass()).getInputStream();
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ int nRead;
+ byte[] data = new byte[16384];
+
+ while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
+ buffer.write(data, 0, nRead);
+ }
+
+ return buffer.toByteArray();
+ }
+
+ // -- DEPENDENCIES
+
+ @Inject PetOwners PetOwners;
+ @Inject ClockService clockService;
+ @Inject FakeDataService fakeDataService;
+ }
+
+ public static class PersistAll
+ extends PersonaEnumPersistAll<PetOwner, PetOwner_persona, Builder> {
+ public PersistAll() {
+ super(PetOwner_persona.class);
+ }
+ }
+
+
+}
diff --git a/module-petowner/src/main/java/domainapp/modules/petowner/types/Name.java b/module-petowner/src/main/java/domainapp/modules/petowner/types/Name.java
new file mode 100644
index 0000000..0e36990
--- /dev/null
+++ b/module-petowner/src/main/java/domainapp/modules/petowner/types/Name.java
@@ -0,0 +1,20 @@
+package domainapp.modules.petowner.types;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.causeway.applib.annotation.Parameter;
+import org.apache.causeway.applib.annotation.ParameterLayout;
+import org.apache.causeway.applib.annotation.Property;
+
+@Property(maxLength = Name.MAX_LEN)
+@Parameter(maxLength = Name.MAX_LEN)
+@ParameterLayout(named = "Name")
+@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Name {
+
+ int MAX_LEN = 40;
+}
diff --git a/module-petowner/src/main/java/domainapp/modules/petowner/types/Notes.java b/module-petowner/src/main/java/domainapp/modules/petowner/types/Notes.java
new file mode 100644
index 0000000..c9bdc1b
--- /dev/null
+++ b/module-petowner/src/main/java/domainapp/modules/petowner/types/Notes.java
@@ -0,0 +1,25 @@
+package domainapp.modules.petowner.types;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.causeway.applib.annotation.Editing;
+import org.apache.causeway.applib.annotation.Parameter;
+import org.apache.causeway.applib.annotation.ParameterLayout;
+import org.apache.causeway.applib.annotation.Property;
+import org.apache.causeway.applib.annotation.PropertyLayout;
+import org.apache.causeway.applib.annotation.Where;
+
+@Property(editing = Editing.ENABLED, maxLength = Notes.MAX_LEN)
+@PropertyLayout(named = "Notes", multiLine = 10, hidden = Where.ALL_TABLES)
+@Parameter(maxLength = Notes.MAX_LEN)
+@ParameterLayout(named = "Notes", multiLine = 10)
+@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Notes {
+
+ int MAX_LEN = 4000;
+
+}
diff --git a/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Bang.docx b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Bang.docx
new file mode 100644
index 0000000..d9a0df3
Binary files /dev/null and b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Bang.docx differ
diff --git a/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Bang.pdf b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Bang.pdf
new file mode 100644
index 0000000..d1b6052
Binary files /dev/null and b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Bang.pdf differ
diff --git a/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Bar.docx b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Bar.docx
new file mode 100644
index 0000000..017b363
Binary files /dev/null and b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Bar.docx differ
diff --git a/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Bar.pdf b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Bar.pdf
new file mode 100644
index 0000000..a50b5c7
Binary files /dev/null and b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Bar.pdf differ
diff --git a/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Fizz.docx b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Fizz.docx
new file mode 100644
index 0000000..840a4a1
Binary files /dev/null and b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Fizz.docx differ
diff --git a/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Fizz.pdf b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Fizz.pdf
new file mode 100644
index 0000000..f95c8a7
Binary files /dev/null and b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Fizz.pdf differ
diff --git a/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Foo.docx b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Foo.docx
new file mode 100644
index 0000000..c527689
Binary files /dev/null and b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Foo.docx differ
diff --git a/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Foo.pdf b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Foo.pdf
new file mode 100644
index 0000000..7451793
Binary files /dev/null and b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Foo.pdf differ
diff --git a/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Frodo.docx b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Frodo.docx
new file mode 100644
index 0000000..27e9031
Binary files /dev/null and b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Frodo.docx differ
diff --git a/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Frodo.pdf b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Frodo.pdf
new file mode 100644
index 0000000..4021c2c
Binary files /dev/null and b/module-petowner/src/main/resources/domainapp/modules/petowner/fixture/Frodo.pdf differ