petclinic-uml
Object Oriented Software Engineering: OOA and OOD of the Spring Petclinc using UML.
What is it?
These Demo Application are planned to be a “Rosetta Stone” for compare OOP Web Application Frameworks like
- Jakarta EE (Java)
- Java EE 7
- Java EE 6
- Symfony (PHP)
- Django (Python)
- Flask with SQLalchemy (Python)
- Fluid,Extbase (TYPO3-CMS, PHP)
This OOA and OOD should extract and divide the functional Requirements from the nonfunctional Requirements of the Frameworks.
- Most of the Frameworks compared here use Model-2 MVC Pattern for the Web/Presentation-Tier but Jakarta EE uses JSF (Java Server Faces), a Component Based Web/Presentation-Tier.
This Specification should also serve as Specification for non-Web Frontends like:
Why Petclinic?
- The Domain Classes show all relationships like one-to-many (1:n), many-to-one (n:1) and many-to-many (n:m)
- It is simple enough but yet it shows more than just the CRUD Use Cases (Create, Read, Update, Delete) of most Demos and Training Examples.
- You can think of it as smallest complete Web App with the usual things to solve.
Functional Requirements
Object Oriented Design
Petclinic Overview
Petclinic Domain Class Modell
Petclinic Use Case Diagram
Application
Vet and Specialty
Specialty
Specialty Use Case Diagram
Specialty Use Case and State Table
Specialty Use Cases | Specialty States | Frontend |
---|---|---|
Specialty.list | SPECIALTY_LIST_EMPTY | Disable Search-Button and Paging-Widget |
Specialty.list | SPECIALTY_LIST | |
Specialty.search * | SPECIALTY_LIST_SEARCH_RESULT | |
Specialty.addNew | SPECIALTY_NEW | |
Specialty.details | SPECIALTY_DETAILS | |
Specialty.edit | SPECIALTY_EDIT | |
Specialty.delete | SPECIALTY_DELETE |
*) TODO
Specialty State Diagram
Specialty State Table
PetType Use Cases | Actions | Frontend to View | View to Backend (DB) | outcome | precondition | postcondition |
---|---|---|---|---|---|---|
Specialty.list | SpecialtyView.button_list_dialog() | x, calls: SpecialtyView.load_list() | change state | length(list(Specialty)) == 0 | SPECIALTY_LIST_EMPTY | |
Specialty.list | SpecialtyView.button_list_dialog() | x, calls: SpecialtyView.load_list() | change state | length(list(Specialty)) > 0 | SPECIALTY_LIST | |
Specialty.list | SpecialtyView.load_list() | x | list(Specialty) | length(list(Specialty)) == 0 | SPECIALTY_LIST_EMPTY | |
Specialty.list | SpecialtyView.load_list() | x | list(Specialty) | length(list(Specialty)) > 0 | SPECIALTY_LIST | |
Specialty.addNew | SpecialtyView.button_addNew_dialog() | x | change state | SPECIALTY_LIST | SPECIALTY_NEW | |
Specialty.addNew | SpecialtyView.button_cancel_and_back() | x | change state | SPECIALTY_NEW | SPECIALTY_LIST | |
Specialty.addNew | SpecialtyView.button_addNew_perform() | x, calls: SpecialtyView.db_addNew() | if OK: change state | SPECIALTY_NEW | SPECIALTY_DETAILS | |
Specialty.addNew | SpecialtyView.db_addNew() | x | OK | length(list(Specialty)) = n | length(list(Specialty)) = n+1 | |
Specialty.addNew | SpecialtyView.db_addNew() | x | not OK, invalid | length(list(Specialty)) = n | display cause as flash message | |
Specialty.details | SpecialtyView.button_detail_dialog() | x | change state | SPECIALTY_LIST | SPECIALTY_DETAILS | |
Specialty.details | SpecialtyView.button_detail_dialog() | x | change state | SPECIALTY_LIST_EMPTY | SPECIALTY_DETAILS | |
Specialty.edit | SpecialtyView.button_edit_dialog() | x | change state | SPECIALTY_DETAILS | SPECIALTY_EDIT | |
Specialty.edit | SpecialtyView.button_cancel_and_back() | x | change state | SPECIALTY_EDIT | SPECIALTY_LIST | |
Specialty.edit | SpecialtyView.button_update_perform() | x, calls: SpecialtyView.db_update() | if OK: change state | SPECIALTY_EDIT | SPECIALTY_DETAILS | |
Specialty.edit | SpecialtyView.db_update() | x | OK | length(list(Specialty)) = n > 0 | length(list(Specialty)) = n; 1 element changed | |
Specialty.edit | SpecialtyView.db_update() | x | not OK, invalid | length(list(Specialty)) = n >= 0 | display cause as flash message | |
Specialty.delete | SpecialtyView.button_delete_dialog() | x | change state | SPECIALTY_DETAILS | SPECIALTY_DELETE | |
Specialty.delete | SpecialtyView.button_cancel_and_back() | x | change state | SPECIALTY_DELETE | SPECIALTY_LIST | |
Specialty.delete | SpecialtyView.button_delete_perform() | x, calls: SpecialtyView.db_delete() | if OK: change state | SPECIALTY_DELETE | SPECIALTY_DETAILS | |
Specialty.delete | SpecialtyView.db_delete() | x | OK | length(list(Specialty)) = n > 0 | length(list(Specialty)) = n-1 | |
Specialty.delete | SpecialtyView.db_delete() | x | not OK, invalid | length(list(Specialty)) = n >= 0 | display cause as flash message |
Vet
Vet Use Case Diagram
Vet Use Case and State Table
Use Case | Vetinarian States | Frontend |
---|---|---|
Vet.list | VET_LIST_EMPTY | Disable Search-Button and Paging-Widget |
Vet.list | VET_LIST | |
Vet.search * | VET_LIST_SEARCH_RESULT | |
Vet.addNew | VET_NEW | |
Vet.details | vet_DETAILS | |
Vet.details | VET_DETAILS | |
Vet.edit | VET_EDIT | |
Vet.delete | VET_DELETE |
*) TODO
Vet State Diagram
Vet State Table
PetType Use Cases | Actions | Frontend to View | View to Backend (DB) | outcome | precondition | postcondition |
---|---|---|---|---|---|---|
Vet.list | VetView.button_list_dialog() | x, calls: VetView.load_list() | change state | length(list(Vet)) == 0 | VET_LIST_EMPTY | |
Vet.list | VetView.button_list_dialog() | x, calls: VetView.load_list() | change state | length(list(Vet)) > 0 | VET_LIST | |
Vet.list | VetView.load_list() | x | list(Vet) | length(list(Vet)) == 0 | VET_LIST_EMPTY | |
Vet.list | VetView.load_list() | x | list(Vet) | length(list(Vet)) > 0 | VET_LIST | |
Vet.addNew | VetView.button_addNew_dialog() | x | change state | VET_LIST | VET_NEW | |
Vet.addNew | VetView.button_cancel_and_back() | x | change state | VET_NEW | VET_LIST | |
Vet.addNew | VetView.button_addNew_perform() | x, calls: VetView.db_addNew() | if OK: change state | VET_NEW | VET_DETAILS | |
Vet.addNew | VetView.db_addNew() | x | OK | length(list(Vet)) = n | length(list(Vet)) = n+1 | |
Vet.addNew | VetView.db_addNew() | x | not OK, invalid | length(list(Vet)) = n | display cause as flash message | |
Vet.details | VetView.button_detail_dialog() | x | change state | VET_LIST | VET_DETAILS | |
Vet.details | VetView.button_detail_dialog() | x | change state | VET_LIST_EMPTY | VET_DETAILS | |
Vet.edit | VetView.button_edit_dialog() | x | change state | VET_DETAILS | VET_EDIT | |
Vet.edit | VetView.button_cancel_and_back() | x | change state | VET_EDIT | VET_LIST | |
Vet.edit | VetView.button_update_perform() | x, calls: VetView.db_update() | if OK: change state | VET_EDIT | VET_DETAILS | |
Vet.edit | VetView.db_update() | x | OK | length(list(Vet)) = n > 0 | length(list(Vet)) = n; 1 element changed | |
Vet.edit | VetView.db_update() | x | not OK, invalid | length(list(Vet)) = n >= 0 | display cause as flash message | |
Vet.delete | VetView.button_delete_dialog() | x | change state | VET_DETAILS | VET_DELETE | |
Vet.delete | VetView.button_cancel_and_back() | x | change state | VET_DELETE | VET_LIST | |
Vet.delete | VetView.button_delete_perform() | x, calls: VetView.db_delete() | if OK: change state | VET_DELETE | VET_DETAILS | |
Vet.delete | VetView.db_delete() | x | OK | length(list(Vet)) = n > 0 | length(list(Vet)) = n-1 | |
Vet.delete | VetView.db_delete() | x | not OK, invalid | length(list(Vet)) = n >= 0 | display cause as flash message |
VetView and SpecialtyView Class Diagram
Specialty and Vet DB Backend: vet.oodm
Owner and PetType
PetType
PetType Use Case Diagram
PetType Use Cases and States Table
PetType States | PetType Use Cases | Frontend |
---|---|---|
PetType.list | PETTYPE_LIST_EMPTY | Disable Search-Button and Paging-Widget |
PetType.list | PETTYPE_LIST | |
PetType.search * | PETTYPE_LIST_SEARCH_RESULT | |
PetType.addNew | PETTYPE_NEW | |
PetType.details | PETTYPE_DETAILS | |
PetType.edit | PETTYPE_EDIT | |
PetType.delete | PETTYPE_DELETE |
*) TODO
PetType State Diagram
PetType State Table
PetType Use Cases | Actions | Frontend to View | View to Backend (DB) | outcome | precondition | postcondition |
---|---|---|---|---|---|---|
PetType.list | PetTypeView.button_list_dialog() | x, calls: PetType.load_list() | change state | length(list(PetType)) == 0 | PETTYPE_LIST_EMPTY | |
PetType.list | PetTypeView.button_list_dialog() | x, calls: PetType.load_list() | change state | length(list(PetType)) > 0 | PETTYPE_LIST | |
PetType.list | PetTypeView.load_list() | x | list(PetType) | length(list(PetType)) == 0 | PETTYPE_LIST_EMPTY | |
PetType.list | PetTypeView.load_list() | x | list(PetType) | length(list(PetType)) > 0 | PETTYPE_LIST | |
PetType.addNew | PetTypeView.button_addNew_dialog() | x | change state | PETTYPE_LIST | PETTYPE_NEW | |
PetType.addNew | PetTypeView.button_cancel_and_back() | x | change state | PETTYPE_NEW | PETTYPE_LIST | |
PetType.addNew | PetTypeView.button_addNew_perform() | x, calls: PetType.db_addNew() | if OK: change state | PETTYPE_NEW | PETTYPE_DETAILS | |
PetType.addNew | PetTypeView.db_addNew() | x | OK | length(list(PetType)) = n | length(list(PetType)) = n+1 | |
PetType.addNew | PetTypeView.db_addNew() | x | not OK, invalid | length(list(PetType)) = n | display cause as flash message | |
PetType.details | PetTypeView.button_detail_dialog() | x | change state | PETTYPE_LIST | PETTYPE_DETAILS | |
PetType.details | PetTypeView.button_detail_dialog() | x | change state | PETTYPE_LIST_EMPTY | PETTYPE_DETAILS | |
PetType.edit | PetTypeView.button_edit_dialog() | x | change state | PETTYPE_DETAILS | PETTYPE_EDIT | |
PetType.edit | PetTypeView.button_cancel_and_back() | x | change state | PETTYPE_EDIT | PETTYPE_LIST | |
PetType.edit | PetTypeView.button_update_perform() | x, calls: PetType.db_update() | if OK: change state | PETTYPE_EDIT | PETTYPE_DETAILS | |
PetType.edit | PetTypeView.db_update() | x | OK | length(list(PetType)) = n > 0 | length(list(PetType)) = n; 1 element changed | |
PetType.edit | PetTypeView.db_update() | x | not OK, invalid | length(list(PetType)) = n >= 0 | display cause as flash message | |
PetType.delete | PetTypeView.button_delete_dialog() | x | change state | PETTYPE_DETAILS | PETTYPE_DELETE | |
PetType.delete | PetTypeView.button_cancel_and_back() | x | change state | PETTYPE_DELETE | PETTYPE_LIST | |
PetType.delete | PetTypeView.button_delete_perform() | x, calls: PetType.db_delete() | if OK: change state | PETTYPE_DELETE | PETTYPE_DETAILS | |
PetType.delete | PetTypeView.db_delete() | x | OK | length(list(PetType)) = n > 0 | length(list(PetType)) = n-1 | |
PetType.delete | PetTypeView.db_delete() | x | not OK, invalid | length(list(PetType)) = n >= 0 | display cause as flash message |
Owner
Owner Use Cases
Owner State
Use Case | Owner States | Frontend |
---|---|---|
Owner.list * | OWNER_LIST_EMPTY | Disable Edit-, Delete-, Search-Button and Paging-Widget |
Owner.list * | OWNER_LIST | |
Owner.list * | OWNER_LIST_SEARCH_RESULT | |
Owner.addNew | OWNER_NEW | |
Owner.details | OWNER_DETAILS | |
Owner.edit | OWNER_EDIT | |
Owner.delete | OWNER_DELETE | |
Owner.Pet.addNew | OWNER_PET_NEW | |
Owner.Pet.edit | OWNER_PET_EDIT | |
Owner.Pet.delete | OWNER_PET_DELETE | |
Owner.Pet.Visit.addNew | OWNER_PET_VISIT_NEW | |
Owner.Pet.Visit.edit | OWNER_PET_VISIT_EDIT | |
Owner.Pet.Visit.delete | OWNER_PET_VISIT_DELETE |
*) TODO
Owner State Diagram
Owner State Diagram
Owner State Table
Use Case | Actions | Frontend to View | View to Backend (DB) | outcome | precondition | postcondition |
---|---|---|---|---|---|---|
Owner.list | OwnerView.button_list_dialog() | x, calls: VetView.load_list() | change state | length(list(Owner)) == 0 | OWNER_LIST_EMPTY | |
Owner.list | OwnerView.button_list_dialog() | x, calls: VetView.load_list() | change state | length(list(Owner)) > 0 | OWNER_LIST | |
Owner.list | OwnerView.load_list() | x | list(Owner) | length(list(Owner)) == 0 | OWNER_LIST_EMPTY | |
Owner.list | OwnerView.load_list() | x | list(Owner) | length(list(Owner)) > 0 | OWNER_LIST | |
Owner.addNew | OwnerView.button_owner_addNew_dialog() | x | change state | OWNER_LIST | OWNER_NEW | |
Owner.addNew | OwnerView.button_owner_cancel_and_back() | x | change state | OWNER_NEW | OWNER_LIST | |
Owner.addNew | OwnerView.button_owner_addNew_perform() | x, calls: Owner.db_owner_addNew() | if OK: change state | OWNER_NEW | OWNER_LIST | |
Owner.addNew | OwnerView.db_owner_addNew() | x | OK | length(list(Owner)) = n | length(list(Owner)) = n+1 | |
Owner.addNew | OwnerView.db_owner_addNew() | x | not OK, invalid | length(list(Owner)) = n | display cause as flash message | |
Owner.details | OwnerView.button_owner_details_dialog() | x | change state | OWNER_LIST | OWNER_DETAILS | |
Owner.details | OwnerView.button_owner_back_to_list() | x | change state | OWNER_DETAILS | OWNER_LIST | |
Owner.edit | OwnerView.button_owner_edit_dialog() | x | change state | OWNER_DETAILS | OWNER_EDIT | |
Owner.edit | OwnerView.button_owner_cancel_and_back() | x | change state | OWNER_EDIT | OWNER_DETAILS | |
Owner.edit | OwnerView.button_owner_update_perform() | x, calls: Owner.db_owner_update() | if OK: change state | OWNER_EDIT | OWNER_DETAILS | |
Owner.edit | OwnerView.db_owner_update() | x | OK | length(list(Owner)) = n > 0 | length(list(Owner)) = n; 1 element changed | |
Owner.edit | OwnerView.db_owner_update() | x | not OK, invalid | length(list(Owner)) = n >= 0 | display cause as flash message | |
Owner.delete | OwnerView.button_owner_delete_dialog() | x | change state | OWNER_DETAILS | OWNER_DELETE | |
Owner.delete | OwnerView.button_owner_cancel_and_back() | x | change state | OWNER_DELETE | OWNER_DETAILS | |
Owner.delete | OwnerView.button_owner_delete_perform() | x, calls: Owner.db_owner_delete() | if OK: change state | OWNER_DELETE | OWNER_DETAILS | |
Owner.delete | OwnerView.db_owner_delete() | x | OK | length(list(Owner)) = n > 0 | length(list(Owner)) = n-1 | |
Owner.delete | OwnerView.db_owner_delete() | x | not OK, invalid | length(list(Owner)) = n >= 0 | display cause as flash message | |
Owner.Pet.addNew | OwnerView.button_pet_addNew_dialog() | x | change state | OWNER_DETAILS | OWNER_PET_NEW | |
Owner.Pet.addNew | OwnerView.button_pet_addNew_perform() | x, calls: Owner.db_pet_addNew() | change state | OWNER_PET_NEW | OWNER_DETAILS | |
Owner.Pet.addNew | OwnerView.db_pet_addNew() | x | OK | length(list(Pet)) = n | length(list(Pet)) = n+1 | |
Owner.Pet.addNew | OwnerView.db_pet_addNew() | x | not OK, invalid | length(list(Pet)) = n | display cause as flash message | |
Owner.Pet.edit | OwnerView.button_pet_edit_dialog() | x | change state | OWNER_DETAILS | OWNER_PET_EDIT | |
Owner.Pet.edit | OwnerView.button_pet_update_perform() | x, calls: Owner.db_pet_update() | change state | OWNER_PET_EDIT | OWNER_DETAILS | |
Owner.Pet.edit | OwnerView.db_pet_update() | x | OK | length(list(Pet)) = n | length(list(Pet)) = n; 1 element changed | |
Owner.Pet.edit | OwnerView.db_pet_update() | x | not OK, invalid | length(list(Pet)) = n | display cause as flash message | |
Owner.Pet.delete | OwnerView.button_pet_delete_dialog() | x | change state | OWNER_DETAILS | OWNER_PET_DELETE | |
Owner.Pet.delete | OwnerView.button_pet_delete_perform() | x, calls: Owner.db_pet_delete() | change state | OWNER_PET_DELETE | OWNER_DETAILS | |
Owner.Pet.delete | OwnerView.db_pet_delete() | x | OK | length(list(Pet)) = n > 0 | length(list(Pet)) = n-1 | |
Owner.Pet.delete | OwnerView.db_pet_delete() | x | not OK, invalid | length(list(Pet)) = n >= 0 | display cause as flash message | |
Owner.Pet.Visit.addNew | OwnerView.button_visit_addNew_dialog() | x | change state | OWNER_DETAILS | OWNER_PET_VISIT_NEW | |
Owner.Pet.Visit.addNew | OwnerView.button_visit_addNew_perform() | x, calls: Owner.db_visit_addNew() | change state | OWNER_PET_VISIT_NEW | OWNER_DETAILS | |
Owner.Pet.Visit.addNew | OwnerView.db_visit_addNew() | x | OK | length(list(Visit)) = n | length(list(Visit)) = n+1 | |
Owner.Pet.Visit.addNew | OwnerView.db_visit_addNew() | x | not OK, invalid | length(list(Visit)) = n | display cause as flash message | |
Owner.Pet.Visit.edit | OwnerView.button_visit_edit_dialog() | x | change state | OWNER_DETAILS | OWNER_PET_VISIT_EDIT | |
Owner.Pet.Visit.edit | OwnerView.button_visit_update_perform() | x, calls: Owner.db_visit_update() | change state | OWNER_PET_VISIT_EDIT | OWNER_DETAILS | |
Owner.Pet.Visit.edit | OwnerView.db_visit_update() | x | OK | length(list(Visit)) = n | length(list(Visit)) = n; 1 element changed | |
Owner.Pet.Visit.edit | OwnerView.db_visit_update() | x | not OK, invalid | length(list(Visit)) = n | display cause as flash message | |
Owner.Pet.Visit.delete | OwnerView.button_visit_delete_dialog() | x | change state | OWNER_DETAILS | OWNER_PET_VISIT_DELETE | |
Owner.Pet.Visit.delete | OwnerView.button_visit_delete_perform() | x, calls: Owner.db_visit_delete() | change state | OWNER_PET_VISIT_DELETE | OWNER_DETAILS | |
Owner.Pet.Visit.delete | OwnerView.db_visit_delete() | x | OK | length(list(Visit)) = n > 0 | length(list(Visit)) = n-1 | |
Owner.Pet.Visit.delete | OwnerView.db_visit_delete() | x | not OK, invalid | length(list(Visit)) = n >= 0 | display cause as flash message |